mirror of
https://github.com/macvim-dev/macvim.git
synced 2026-06-02 11:19:22 +02:00
Compare commits
138 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 204e14b994 | |||
| 2e8bea32db | |||
| e70fb38670 | |||
| 3d56969f47 | |||
| 294d03baf6 | |||
| ac96dc67ba | |||
| 0413dcf3f1 | |||
| 40263195cb | |||
| dd76f85f0b | |||
| e93e9c4201 | |||
| a4a14b39ac | |||
| 49eeb133ac | |||
| 28de969ae3 | |||
| 6961a51e9a | |||
| f679af784b | |||
| fd8e8e0b4f | |||
| cd5ca1918d | |||
| 27d4ee55ae | |||
| 23e38c4298 | |||
| 0486075221 | |||
| 7a010c4a46 | |||
| 9aeade7147 | |||
| 5663536b1f | |||
| 95f42c734a | |||
| e1ece272fa | |||
| 73b5d1837c | |||
| 790f685006 | |||
| a680267d49 | |||
| 5f1547b288 | |||
| 9d9a5983f5 | |||
| 16e57e6189 | |||
| 5d45d4a4d2 | |||
| 0546647038 | |||
| c9ad0b6d4d | |||
| 25306ee0c5 | |||
| 2e024248fa | |||
| 85879328b0 | |||
| 9c530a8030 | |||
| 9105eb1fd0 | |||
| c49868a11f | |||
| 795860de7c | |||
| 90a729a8e4 | |||
| 1a328483b7 | |||
| 5e09d64d77 | |||
| 4591403b7e | |||
| e90f76c1aa | |||
| 8745e4380e | |||
| cd7a1f6539 | |||
| bb21f9f120 | |||
| 38c7ababf6 | |||
| 5aea857883 | |||
| 322b4eec7e | |||
| 886d3d7aed | |||
| b2f7a2f021 | |||
| 4374e9787e | |||
| 080a7c2c6c | |||
| ffef064005 | |||
| d23a68d047 | |||
| c973e12d3e | |||
| 5e0543116b | |||
| d9f633dbb3 | |||
| 32cb07dd61 | |||
| 40ae005819 | |||
| c4e8fcc338 | |||
| 9dbb79f942 | |||
| 031479c46b | |||
| 843a3a41bf | |||
| 01973d329c | |||
| bcfeb7c895 | |||
| 46b250b75f | |||
| 9b06b0a4b2 | |||
| 80b36e7995 | |||
| d29599b7ea | |||
| a63fc2427e | |||
| 393e47945b | |||
| 5100db4427 | |||
| 19ee857237 | |||
| 781ac5b687 | |||
| 9b52c915d9 | |||
| 7a68824771 | |||
| c2aed127ca | |||
| 12b3ecfdcd | |||
| 4143f69655 | |||
| 7a720947c8 | |||
| 9393a4151c | |||
| 95a678d204 | |||
| 68cec2f91b | |||
| 5ed292ebfb | |||
| 6d70e1a179 | |||
| 355d2ec231 | |||
| c6ceb6c969 | |||
| 60c1c58967 | |||
| ba43ddb524 | |||
| 2a032c05b7 | |||
| 8d8aecf662 | |||
| 380d7b2cbf | |||
| 30a12fc740 | |||
| 43050b40f8 | |||
| d5dfed9cfc | |||
| 0e2e98e570 | |||
| d0a875e3af | |||
| b770256474 | |||
| e14b8cd599 | |||
| 938149499b | |||
| 9245af7148 | |||
| a874eae869 | |||
| cca95bae41 | |||
| 243fcce65c | |||
| b8c8a68a5c | |||
| 8502d5f2b2 | |||
| da857362b0 | |||
| 4c50d72cdf | |||
| 9af39a7cb2 | |||
| d4038f59f4 | |||
| 9150d82be1 | |||
| 87694dc1bf | |||
| 22704e2bb4 | |||
| 95676cfcd4 | |||
| 1e901456a5 | |||
| 899f9a6260 | |||
| 6b989afdb1 | |||
| 4f48c32bc3 | |||
| c2ea4b240d | |||
| f81158c840 | |||
| 3950b3a6b1 | |||
| ae65cb89b3 | |||
| f90e3c31ab | |||
| 014700ca55 | |||
| f86423097b | |||
| a4cdb9b1c4 | |||
| 03a1a0ea74 | |||
| 4e1a1cad93 | |||
| e4abcd6741 | |||
| b0f34cac04 | |||
| 9dc3e9172c | |||
| 2e69b16f67 | |||
| 3142e74a3a | |||
| c5b2d1b5b4 |
@@ -3,6 +3,14 @@
|
||||
src/MacVim/MacVim.xcodeproj/*.mode1
|
||||
src/MacVim/MacVim.xcodeproj/*.mode1v3
|
||||
src/MacVim/MacVim.xcodeproj/*.pbxuser
|
||||
src/MacVim/icons/*.pyc
|
||||
src/MacVim/icons/*.ttf
|
||||
src/MacVim/icons/*.reg
|
||||
src/MacVim/icons/*.zip
|
||||
src/MacVim/icons/*.txt
|
||||
src/MacVim/icons/*.so
|
||||
src/MacVim/icons/*.egg-info
|
||||
src/MacVim/icons/build
|
||||
src/MacVim/icons/makeicns/*.o
|
||||
src/MacVim/icons/makeicns/makeicns
|
||||
src/MacVim/PSMTabBarControl/PSMTabBarControl.xcodeproj/*.mode1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
*gui_mac.txt* For Vim version 7.2. Last change: 2009 Jan 08
|
||||
*gui_mac.txt* For Vim version 7.2. Last change: 2009 Mar 15
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bjorn Winckler
|
||||
@@ -117,6 +117,11 @@ really bad once you start using tabs. For example, dropping two files, then
|
||||
dropping two more, and switching back to the first tab would cause weird
|
||||
strings like "((3) of 2)" to appear in the window title.
|
||||
|
||||
*macvim-tablabel*
|
||||
Tab labels only show the tail of the file name to make the tabs more readable
|
||||
when editing files in deeply nested folders. Add the line "set guitablabel="
|
||||
to your .gvimrc file to revert back to the default Vim tab label.
|
||||
|
||||
*macvim-options*
|
||||
These are the non-standard options that MacVim supports:
|
||||
'antialias' 'fullscreen' 'fuoptions'
|
||||
|
||||
@@ -63,7 +63,8 @@ already running vim will never fork in MacVim.
|
||||
"gvim --nofork" does the same as "gvim -f".
|
||||
|
||||
If you want the GUI to run in the foreground always, include the 'f'
|
||||
flag in 'guioptions'. |-f|.
|
||||
flag in 'guioptions'. |-f|. MacVim does not support this flag in
|
||||
'guioptions'.
|
||||
|
||||
==============================================================================
|
||||
2. GUI Resources *gui-resources* *.Xdefaults*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
*if_cscop.txt* For Vim version 7.2. Last change: 2005 Mar 29
|
||||
*if_cscop.txt* For Vim version 7.2. Last change: 2009 Mar 18
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Andy Kahn
|
||||
@@ -131,11 +131,22 @@ The available subcommands are:
|
||||
7 or f: Find this file
|
||||
8 or i: Find files #including this file
|
||||
|
||||
For all types, except 4 and 6, leading white space for {name} is
|
||||
removed. For 4 and 6 there is exactly one space between {querytype}
|
||||
and {name}. Further white space is included in {name}.
|
||||
|
||||
EXAMPLES >
|
||||
:cscope find c vim_free
|
||||
:cscope find 3 vim_free
|
||||
:cscope find 3 vim_free
|
||||
<
|
||||
These two examples perform the same query. >
|
||||
These two examples perform the same query: functions calling
|
||||
"vim_free". >
|
||||
|
||||
:cscope find t initOnce
|
||||
:cscope find t initOnce
|
||||
<
|
||||
The first one searches for the text "initOnce", the second one for
|
||||
" initOnce". >
|
||||
|
||||
:cscope find 0 DEFAULT_TERM
|
||||
<
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
*netbeans.txt* For Vim version 7.2. Last change: 2008 Jun 28
|
||||
*netbeans.txt* For Vim version 7.2. Last change: 2009 Jan 06
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Gordon Prieur et al.
|
||||
@@ -722,8 +722,10 @@ keyAtPos keyName lnum/col
|
||||
of the cursor.
|
||||
New in version 2.1.
|
||||
|
||||
killed A file was closed by the user. Only for files that have been
|
||||
assigned a number by the IDE.
|
||||
killed A file was deleted or wiped out by the user and the buffer
|
||||
annotations have been removed. The bufID number for this
|
||||
buffer has become invalid. Only for files that have been
|
||||
assigned a bufID number by the IDE.
|
||||
|
||||
newDotAndMark off off
|
||||
Reports the position of the cursor being at "off" bytes into
|
||||
|
||||
@@ -3490,6 +3490,8 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
foreground. |gui-fork|
|
||||
Note: Set this option in the vimrc file. The forking may have
|
||||
happened already when the |gvimrc| file is read.
|
||||
MacVim does not support this flag due to limitations with
|
||||
forking on Mac OS X.
|
||||
*'go-i'*
|
||||
'i' Use a Vim icon. For GTK with KDE it is used in the left-upper
|
||||
corner of the window. It's black&white on non-GTK, because of
|
||||
@@ -4273,9 +4275,6 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
be able to execute Normal mode commands.
|
||||
This is the opposite of the 'keymap' option, where characters are
|
||||
mapped in Insert mode.
|
||||
This only works for 8-bit characters. The value of 'langmap' may be
|
||||
specified with multi-byte characters (e.g., UTF-8), but only the lower
|
||||
8 bits of each character will be used.
|
||||
|
||||
Example (for Greek, in UTF-8): *greek* >
|
||||
:set langmap=ΑA,ΒB,ΨC,ΔD,ΕE,ΦF,ΓG,ΗH,ΙI,ΞJ,ΚK,ΛL,ΜM,ΝN,ΟO,ΠP,QQ,ΡR,ΣS,ΤT,ΘU,ΩV,WW,ΧX,ΥY,ΖZ,αa,βb,ψc,δd,εe,φf,γg,ηh,ιi,ξj,κk,λl,μm,νn,οo,πp,qq,ρr,σs,τt,θu,ωv,ςw,χx,υy,ζz
|
||||
|
||||
+464
-461
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf350
|
||||
{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf430
|
||||
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
|
||||
{\colortbl;\red255\green255\blue255;}
|
||||
\vieww9000\viewh8400\viewkind0
|
||||
@@ -40,8 +40,6 @@ Thank you to {\field{\*\fldinst{HYPERLINK "http://www.positivespinmedia.com"}}{\
|
||||
\
|
||||
Toolbar icons by {\field{\*\fldinst{HYPERLINK "http://www.mattballdesign.com/"}}{\fldrslt Matt Ball}} (free Developer Icons), {\field{\*\fldinst{HYPERLINK "http://www.jonasraskdesign.com/"}}{\fldrslt Jonas Rask}} (Danish Royalty Free icon set), and {\field{\*\fldinst{HYPERLINK "http://www.everaldo.com"}}{\fldrslt Everaldo Coelho}} (Crystal Project Icons, released under LGPL license).\
|
||||
\
|
||||
Vim icons made by {\field{\*\fldinst{HYPERLINK "http://www.cs.princeton.edu/~mtwebb/vim_icon/vim_icons.html"}}{\fldrslt Matthew Webb}}.\
|
||||
\
|
||||
The default font in MacVim, DejaVu Sans Mono, is based on the Bitstream Vera\'99 and Arev fonts. Bitstream Vera\'99 is \'a9 2003 by Bitstream, Inc. Arev is \'a9 2006 by Tavmjong Bah. The DejaVu changes to these fonts are in the public domain.\
|
||||
\
|
||||
Thanks to Andy Matuschak for {\field{\*\fldinst{HYPERLINK "http://sparkle.andymatuschak.org/"}}{\fldrslt Sparkle}}.\
|
||||
@@ -52,4 +50,6 @@ Thanks to Allan Odgaard for making the "Edit in TextMate" input manager source c
|
||||
\
|
||||
Thanks to Rainer Brockerhoff for RBSplitView.\
|
||||
\
|
||||
Thanks to Chad Weider for CTGradient.}
|
||||
Thanks to Chad Weider for CTGradient.\
|
||||
\
|
||||
Thanks to Damien Guard for {\field{\*\fldinst{HYPERLINK "http://damieng.com/blog/2008/05/26/envy-code-r-preview-7-coding-font-released"}}{\fldrslt Envy Code R}} (used in MacVim's 16x16 document icons).}
|
||||
@@ -1153,7 +1153,7 @@
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>41</string>
|
||||
<string>45</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
int preloadPid;
|
||||
BOOL shouldActivateWhenNextWindowOpens;
|
||||
int numChildProcesses;
|
||||
NSMutableDictionary *inputQueues;
|
||||
int processingFlag;
|
||||
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4)
|
||||
FSEventStreamRef fsEventStream;
|
||||
|
||||
+244
-104
@@ -125,6 +125,8 @@ typedef struct
|
||||
- (void)loadDefaultFont;
|
||||
- (int)executeInLoginShell:(NSString *)path arguments:(NSArray *)args;
|
||||
- (void)reapChildProcesses:(id)sender;
|
||||
- (void)processInputQueues:(id)sender;
|
||||
- (void)addVimController:(MMVimController *)vc;
|
||||
|
||||
#ifdef MM_ENABLE_PLUGINS
|
||||
- (void)removePlugInMenu;
|
||||
@@ -208,6 +210,7 @@ fsEventCallback(ConstFSEventStreamRef streamRef,
|
||||
cachedVimControllers = [NSMutableArray new];
|
||||
preloadPid = -1;
|
||||
pidArguments = [NSMutableDictionary new];
|
||||
inputQueues = [NSMutableDictionary new];
|
||||
|
||||
#ifdef MM_ENABLE_PLUGINS
|
||||
NSString *plugInTitle = NSLocalizedString(@"Plug-In",
|
||||
@@ -249,6 +252,7 @@ fsEventCallback(ConstFSEventStreamRef streamRef,
|
||||
//NSLog(@"MMAppController dealloc");
|
||||
|
||||
[connection release]; connection = nil;
|
||||
[inputQueues release]; inputQueues = nil;
|
||||
[pidArguments release]; pidArguments = nil;
|
||||
[vimControllers release]; vimControllers = nil;
|
||||
[cachedVimControllers release]; cachedVimControllers = nil;
|
||||
@@ -341,14 +345,17 @@ fsEventCallback(ConstFSEventStreamRef streamRef,
|
||||
// The user default MMUntitledWindow can be set to control whether an
|
||||
// untitled window should open on 'Open' and 'Reopen' events.
|
||||
int untitledWindowFlag = [ud integerForKey:MMUntitledWindowKey];
|
||||
if ([desc eventID] == kAEOpenApplication
|
||||
&& (untitledWindowFlag & MMUntitledWindowOnOpen) == 0)
|
||||
|
||||
BOOL isAppOpenEvent = [desc eventID] == kAEOpenApplication;
|
||||
if (isAppOpenEvent && (untitledWindowFlag & MMUntitledWindowOnOpen) == 0)
|
||||
return NO;
|
||||
else if ([desc eventID] == kAEReopenApplication
|
||||
|
||||
BOOL isAppReopenEvent = [desc eventID] == kAEReopenApplication;
|
||||
if (isAppReopenEvent
|
||||
&& (untitledWindowFlag & MMUntitledWindowOnReopen) == 0)
|
||||
return NO;
|
||||
|
||||
// When a process is started from the command line, the 'Open' event will
|
||||
// When a process is started from the command line, the 'Open' event may
|
||||
// contain a parameter to surpress the opening of an untitled window.
|
||||
desc = [desc paramDescriptorForKeyword:keyAEPropData];
|
||||
desc = [desc paramDescriptorForKeyword:keyMMUntitledWindow];
|
||||
@@ -361,8 +368,12 @@ fsEventCallback(ConstFSEventStreamRef streamRef,
|
||||
return NO;
|
||||
|
||||
// NOTE! This way it possible to start the app with the command-line
|
||||
// argument '-nowindow yes' and no window will be opened by default.
|
||||
return ![ud boolForKey:MMNoWindowKey];
|
||||
// argument '-nowindow yes' and no window will be opened by default but
|
||||
// this argument will only be heeded when the application is opening.
|
||||
if (isAppOpenEvent && [ud boolForKey:MMNoWindowKey] == YES)
|
||||
return NO;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)applicationOpenUntitledFile:(NSApplication *)sender
|
||||
@@ -669,21 +680,26 @@ fsEventCallback(ConstFSEventStreamRef streamRef,
|
||||
|
||||
[win setFrameTopLeftPoint:topLeft];
|
||||
|
||||
NSPoint screenOrigin = [[win screen] frame].origin;
|
||||
if ([win frame].origin.y < screenOrigin.y) {
|
||||
// Try to avoid shifting the new window downwards if it means that
|
||||
// the bottom of the window will be off the screen. E.g. if the
|
||||
// user has set windows to open maximized in the vertical direction
|
||||
// then the new window will cascade horizontally only.
|
||||
topLeft.y = oldTopLeft.y;
|
||||
[win setFrameTopLeftPoint:topLeft];
|
||||
}
|
||||
if ([win screen]) {
|
||||
NSPoint screenOrigin = [[win screen] frame].origin;
|
||||
if ([win frame].origin.y < screenOrigin.y) {
|
||||
// Try to avoid shifting the new window downwards if it means
|
||||
// that the bottom of the window will be off the screen. E.g.
|
||||
// if the user has set windows to open maximized in the
|
||||
// vertical direction then the new window will cascade
|
||||
// horizontally only.
|
||||
topLeft.y = oldTopLeft.y;
|
||||
[win setFrameTopLeftPoint:topLeft];
|
||||
}
|
||||
|
||||
if ([win frame].origin.y < screenOrigin.y) {
|
||||
// Move the window to the top of the screen if the bottom of the
|
||||
// window is still obscured.
|
||||
topLeft.y = NSMaxY([[win screen] frame]);
|
||||
[win setFrameTopLeftPoint:topLeft];
|
||||
if ([win frame].origin.y < screenOrigin.y) {
|
||||
// Move the window to the top of the screen if the bottom of
|
||||
// the window is still obscured.
|
||||
topLeft.y = NSMaxY([[win screen] frame]);
|
||||
[win setFrameTopLeftPoint:topLeft];
|
||||
}
|
||||
} else {
|
||||
NSLog(@"[%s] WINDOW NOT ON SCREEN, don't constrain position", _cmd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -830,6 +846,17 @@ fsEventCallback(ConstFSEventStreamRef streamRef,
|
||||
firstController = vc;
|
||||
}
|
||||
|
||||
// The meaning of "layout" is defined by the WIN_* defines in main.c.
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
int layout = [ud integerForKey:MMOpenLayoutKey];
|
||||
BOOL splitVert = [ud boolForKey:MMVerticalSplitKey];
|
||||
BOOL openInCurrentWindow = [ud boolForKey:MMOpenInCurrentWindowKey];
|
||||
|
||||
if (splitVert && MMLayoutHorizontalSplit == layout)
|
||||
layout = MMLayoutVerticalSplit;
|
||||
if (layout < 0 || (layout > MMLayoutTabs && openInCurrentWindow))
|
||||
layout = MMLayoutTabs;
|
||||
|
||||
if ([filenames count] == 0) {
|
||||
// Raise the window containing the first file that was already open,
|
||||
// and make sure that the tab containing that file is selected. Only
|
||||
@@ -837,10 +864,18 @@ fsEventCallback(ConstFSEventStreamRef streamRef,
|
||||
// the window with 'firstFile' will be raised, other times it might be
|
||||
// the window that will open with the files in the 'filenames' array.
|
||||
firstFile = [firstFile stringByEscapingSpecialFilenameCharacters];
|
||||
|
||||
NSString *bufCmd = @"tab sb";
|
||||
switch (layout) {
|
||||
case MMLayoutHorizontalSplit: bufCmd = @"sb"; break;
|
||||
case MMLayoutVerticalSplit: bufCmd = @"vert sb"; break;
|
||||
case MMLayoutArglist: bufCmd = @"b"; break;
|
||||
}
|
||||
|
||||
NSString *input = [NSString stringWithFormat:@"<C-\\><C-N>"
|
||||
":let oldswb=&swb|let &swb=\"useopen,usetab\"|"
|
||||
"tab sb %@|let &swb=oldswb|unl oldswb|"
|
||||
"cal foreground()<CR>", firstFile];
|
||||
"%@ %@|let &swb=oldswb|unl oldswb|"
|
||||
"cal foreground()<CR>", bufCmd, firstFile];
|
||||
|
||||
[firstController addVimInput:input];
|
||||
|
||||
@@ -857,23 +892,13 @@ fsEventCallback(ConstFSEventStreamRef streamRef,
|
||||
//
|
||||
// b) Open any remaining files
|
||||
//
|
||||
MMVimController *vc;
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
BOOL openInCurrentWindow = [ud boolForKey:MMOpenInCurrentWindowKey];
|
||||
|
||||
// The meaning of "layout" is defined by the WIN_* defines in main.c.
|
||||
int layout = [ud integerForKey:MMOpenLayoutKey];
|
||||
BOOL splitVert = [ud boolForKey:MMVerticalSplitKey];
|
||||
if (splitVert && MMLayoutHorizontalSplit == layout)
|
||||
layout = MMLayoutVerticalSplit;
|
||||
if (layout < 0 || (layout > MMLayoutTabs && openInCurrentWindow))
|
||||
layout = MMLayoutTabs;
|
||||
|
||||
[arguments setObject:[NSNumber numberWithInt:layout] forKey:@"layout"];
|
||||
[arguments setObject:filenames forKey:@"filenames"];
|
||||
// (Indicate that files should be opened from now on.)
|
||||
[arguments setObject:[NSNumber numberWithBool:NO] forKey:@"dontOpen"];
|
||||
|
||||
MMVimController *vc;
|
||||
if (openInCurrentWindow && (vc = [self topmostVimController])) {
|
||||
// Open files in an already open window.
|
||||
[[[vc windowController] window] makeKeyAndOrderFront:self];
|
||||
@@ -973,7 +998,7 @@ fsEventCallback(ConstFSEventStreamRef streamRef,
|
||||
|
||||
NSOpenPanel *panel = [NSOpenPanel openPanel];
|
||||
[panel setAllowsMultipleSelection:YES];
|
||||
[panel setAccessoryView:openPanelAccessoryView()];
|
||||
[panel setAccessoryView:showHiddenFilesView()];
|
||||
|
||||
int result = [panel runModalForDirectory:dir file:nil types:nil];
|
||||
if (NSOKButton == result)
|
||||
@@ -1072,64 +1097,79 @@ fsEventCallback(ConstFSEventStreamRef streamRef,
|
||||
}
|
||||
}
|
||||
|
||||
- (byref id <MMFrontendProtocol>)
|
||||
connectBackend:(byref in id <MMBackendProtocol>)backend
|
||||
pid:(int)pid
|
||||
- (MMVimController *)keyVimController
|
||||
{
|
||||
//NSLog(@"Connect backend (pid=%d)", pid);
|
||||
NSNumber *pidKey = [NSNumber numberWithInt:pid];
|
||||
MMVimController *vc = nil;
|
||||
|
||||
@try {
|
||||
[(NSDistantObject*)backend
|
||||
setProtocolForProxy:@protocol(MMBackendProtocol)];
|
||||
|
||||
vc = [[[MMVimController alloc] initWithBackend:backend pid:pid]
|
||||
autorelease];
|
||||
|
||||
if (preloadPid == pid) {
|
||||
// This backend was preloaded, so add it to the cache and schedule
|
||||
// another vim process to be preloaded.
|
||||
preloadPid = -1;
|
||||
[vc setIsPreloading:YES];
|
||||
[cachedVimControllers addObject:vc];
|
||||
[self scheduleVimControllerPreloadAfterDelay:1];
|
||||
|
||||
return vc;
|
||||
NSWindow *keyWindow = [NSApp keyWindow];
|
||||
if (keyWindow) {
|
||||
unsigned i, count = [vimControllers count];
|
||||
for (i = 0; i < count; ++i) {
|
||||
MMVimController *vc = [vimControllers objectAtIndex:i];
|
||||
if ([[[vc windowController] window] isEqual:keyWindow])
|
||||
return vc;
|
||||
}
|
||||
|
||||
[vimControllers addObject:vc];
|
||||
|
||||
id args = [pidArguments objectForKey:pidKey];
|
||||
if (args && [NSNull null] != args)
|
||||
[vc passArguments:args];
|
||||
|
||||
// HACK! MacVim does not get activated if it is launched from the
|
||||
// terminal, so we forcibly activate here unless it is an untitled
|
||||
// window opening. Untitled windows are treated differently, else
|
||||
// MacVim would steal the focus if another app was activated while the
|
||||
// untitled window was loading.
|
||||
if (!args || args != [NSNull null])
|
||||
[self activateWhenNextWindowOpens];
|
||||
|
||||
if (args)
|
||||
[pidArguments removeObjectForKey:pidKey];
|
||||
|
||||
return vc;
|
||||
}
|
||||
|
||||
@catch (NSException *e) {
|
||||
NSLog(@"Exception caught in %s: \"%@\"", _cmd, e);
|
||||
|
||||
if (vc)
|
||||
[vimControllers removeObject:vc];
|
||||
|
||||
[pidArguments removeObjectForKey:pidKey];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (unsigned)connectBackend:(byref in id <MMBackendProtocol>)proxy pid:(int)pid
|
||||
{
|
||||
//NSLog(@"[%s] pid=%d", _cmd, pid);
|
||||
|
||||
[(NSDistantObject*)proxy setProtocolForProxy:@protocol(MMBackendProtocol)];
|
||||
|
||||
// NOTE: Allocate the vim controller now but don't add it to the list of
|
||||
// controllers since this is a distributed object call and as such can
|
||||
// arrive at unpredictable times (e.g. while iterating the list of vim
|
||||
// controllers).
|
||||
// (What if input arrives before the vim controller is added to the list of
|
||||
// controllers? This should not be a problem since the input isn't
|
||||
// processed immediately (see processInput:forIdentifier:).)
|
||||
MMVimController *vc = [[MMVimController alloc] initWithBackend:proxy
|
||||
pid:pid];
|
||||
[self performSelector:@selector(addVimController:)
|
||||
withObject:vc
|
||||
afterDelay:0];
|
||||
|
||||
[vc release];
|
||||
|
||||
return [vc identifier];
|
||||
}
|
||||
|
||||
- (oneway void)processInput:(in bycopy NSArray *)queue
|
||||
forIdentifier:(unsigned)identifier
|
||||
{
|
||||
// NOTE: Input is not handled immediately since this is a distribued object
|
||||
// call and as such can arrive at unpredictable times. Instead, queue the
|
||||
// input and process it when the run loop is updated.
|
||||
|
||||
if (!(queue && identifier)) {
|
||||
NSLog(@"[%s] Bad input for identifier=%d", _cmd, identifier);
|
||||
return;
|
||||
}
|
||||
|
||||
//NSLog(@"[%s] QUEUE for identifier=%d: <<< %@>>>", _cmd, identifier,
|
||||
// debugStringForMessageQueue(queue));
|
||||
|
||||
NSNumber *key = [NSNumber numberWithUnsignedInt:identifier];
|
||||
NSArray *q = [inputQueues objectForKey:key];
|
||||
if (q) {
|
||||
q = [q arrayByAddingObjectsFromArray:queue];
|
||||
[inputQueues setObject:q forKey:key];
|
||||
} else {
|
||||
[inputQueues setObject:queue forKey:key];
|
||||
}
|
||||
|
||||
// NOTE: We must use "event tracking mode" as well as "default mode",
|
||||
// otherwise the input queue will not be processed e.g. during live
|
||||
// resizing.
|
||||
[self performSelector:@selector(processInputQueues:)
|
||||
withObject:nil
|
||||
afterDelay:0
|
||||
inModes:[NSArray arrayWithObjects:NSDefaultRunLoopMode,
|
||||
NSEventTrackingRunLoopMode, nil]];
|
||||
}
|
||||
|
||||
- (NSArray *)serverList
|
||||
{
|
||||
NSMutableArray *array = [NSMutableArray array];
|
||||
@@ -1144,21 +1184,6 @@ fsEventCallback(ConstFSEventStreamRef streamRef,
|
||||
return array;
|
||||
}
|
||||
|
||||
- (MMVimController *)keyVimController
|
||||
{
|
||||
NSWindow *keyWindow = [NSApp keyWindow];
|
||||
if (keyWindow) {
|
||||
unsigned i, count = [vimControllers count];
|
||||
for (i = 0; i < count; ++i) {
|
||||
MMVimController *vc = [vimControllers objectAtIndex:i];
|
||||
if ([[[vc windowController] window] isEqual:keyWindow])
|
||||
return vc;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end // MMAppController
|
||||
|
||||
|
||||
@@ -1315,10 +1340,21 @@ fsEventCallback(ConstFSEventStreamRef streamRef,
|
||||
}
|
||||
|
||||
if (-1 != pid) {
|
||||
// Add a null argument to the pidArguments dictionary. This is later
|
||||
// used to detect that a process without arguments is being launched.
|
||||
[pidArguments setObject:[NSNull null]
|
||||
forKey:[NSNumber numberWithInt:pid]];
|
||||
// The 'pidArguments' dictionary keeps arguments to be passed to the
|
||||
// process when it connects (this is in contrast to arguments which are
|
||||
// passed on the command line, like '-f' and '-g').
|
||||
// If this method is called with nil arguments we take this as a hint
|
||||
// that this is an "untitled window" being launched and add a null
|
||||
// object to the 'pidArguments' dictionary. This way we can detect if
|
||||
// an untitled window is being launched by looking for null objects in
|
||||
// this dictionary.
|
||||
// If this method is called with non-nil arguments then it is assumed
|
||||
// that the caller takes care of adding items to 'pidArguments' as
|
||||
// necessary (only some arguments are passed on connect, e.g. files to
|
||||
// open).
|
||||
if (!args)
|
||||
[pidArguments setObject:[NSNull null]
|
||||
forKey:[NSNumber numberWithInt:pid]];
|
||||
} else {
|
||||
NSLog(@"WARNING: %s%@ failed (useLoginShell=%d)", _cmd, args,
|
||||
useLoginShell);
|
||||
@@ -2083,4 +2119,108 @@ fsEventCallback(ConstFSEventStreamRef streamRef,
|
||||
}
|
||||
}
|
||||
|
||||
- (void)processInputQueues:(id)sender
|
||||
{
|
||||
// NOTE: Because we use distributed objects it is quite possible for this
|
||||
// function to be re-entered. This can cause all sorts of unexpected
|
||||
// problems so we guard against it here so that the rest of the code does
|
||||
// not need to worry about it.
|
||||
|
||||
// The processing flag is > 0 if this function is already on the call
|
||||
// stack; < 0 if this function was also re-entered.
|
||||
if (processingFlag != 0) {
|
||||
NSLog(@"[%s] BUSY!", _cmd);
|
||||
processingFlag = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: Be _very_ careful that no exceptions can be raised between here
|
||||
// and the point at which 'processingFlag' is reset. Otherwise the above
|
||||
// test could end up always failing and no input queues would ever be
|
||||
// processed!
|
||||
processingFlag = 1;
|
||||
|
||||
// NOTE: New input may arrive while we're busy processing; we deal with
|
||||
// this by putting the current queue aside and creating a new input queue
|
||||
// for future input.
|
||||
NSDictionary *queues = inputQueues;
|
||||
inputQueues = [NSMutableDictionary new];
|
||||
|
||||
// Pass each input queue on to the vim controller with matching
|
||||
// identifier (and note that it could be cached).
|
||||
NSEnumerator *e = [queues keyEnumerator];
|
||||
NSNumber *key;
|
||||
while ((key = [e nextObject])) {
|
||||
unsigned ukey = [key unsignedIntValue];
|
||||
int i = 0, count = [vimControllers count];
|
||||
for (i = 0; i < count; ++i) {
|
||||
MMVimController *vc = [vimControllers objectAtIndex:i];
|
||||
if (ukey == [vc identifier]) {
|
||||
[vc processInputQueue:[queues objectForKey:key]]; // !exceptions
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i < count) continue;
|
||||
|
||||
count = [cachedVimControllers count];
|
||||
for (i = 0; i < count; ++i) {
|
||||
MMVimController *vc = [cachedVimControllers objectAtIndex:i];
|
||||
if (ukey == [vc identifier]) {
|
||||
[vc processInputQueue:[queues objectForKey:key]]; // !exceptions
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == count)
|
||||
NSLog(@"[%s] WARNING: No Vim controller for identifier=%d",
|
||||
_cmd, ukey);
|
||||
}
|
||||
|
||||
[queues release];
|
||||
|
||||
// If new input arrived while we were processing it would have been
|
||||
// blocked so we have to schedule it to be processed again.
|
||||
if (processingFlag < 0)
|
||||
[self performSelector:@selector(processInputQueues:)
|
||||
withObject:nil
|
||||
afterDelay:0
|
||||
inModes:[NSArray arrayWithObjects:NSDefaultRunLoopMode,
|
||||
NSEventTrackingRunLoopMode, nil]];
|
||||
|
||||
processingFlag = 0;
|
||||
}
|
||||
|
||||
- (void)addVimController:(MMVimController *)vc
|
||||
{
|
||||
int pid = [vc pid];
|
||||
NSNumber *pidKey = [NSNumber numberWithInt:pid];
|
||||
|
||||
if (preloadPid == pid) {
|
||||
// This controller was preloaded, so add it to the cache and
|
||||
// schedule another vim process to be preloaded.
|
||||
preloadPid = -1;
|
||||
[vc setIsPreloading:YES];
|
||||
[cachedVimControllers addObject:vc];
|
||||
[self scheduleVimControllerPreloadAfterDelay:1];
|
||||
} else {
|
||||
[vimControllers addObject:vc];
|
||||
|
||||
id args = [pidArguments objectForKey:pidKey];
|
||||
if (args && [NSNull null] != args)
|
||||
[vc passArguments:args];
|
||||
|
||||
// HACK! MacVim does not get activated if it is launched from the
|
||||
// terminal, so we forcibly activate here unless it is an untitled
|
||||
// window opening. Untitled windows are treated differently, else
|
||||
// MacVim would steal the focus if another app was activated while the
|
||||
// untitled window was loading.
|
||||
if (!args || args != [NSNull null])
|
||||
[self activateWhenNextWindowOpens];
|
||||
|
||||
if (args)
|
||||
[pidArguments removeObjectForKey:pidKey];
|
||||
}
|
||||
}
|
||||
|
||||
@end // MMAppController (Private)
|
||||
|
||||
@@ -1139,7 +1139,7 @@ defaultLineHeightForFont(NSFont *font)
|
||||
|
||||
if (flags & DRAW_UNDERL)
|
||||
{
|
||||
[fg set];
|
||||
[sp set];
|
||||
NSRectFill(NSMakeRect(rect.origin.x,
|
||||
(row + 1) * cellSize.height + kUnderlineOffset,
|
||||
rect.size.width, kUnderlineHeight));
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
NSMutableArray *inputQueue;
|
||||
NSMutableData *drawData;
|
||||
NSConnection *connection;
|
||||
id frontendProxy;
|
||||
id appProxy;
|
||||
unsigned identifier;
|
||||
NSDictionary *colorDict;
|
||||
NSDictionary *sysColorDict;
|
||||
NSDictionary *actionDict;
|
||||
|
||||
+32
-40
@@ -21,7 +21,7 @@
|
||||
*
|
||||
* It is very important to realize that all state is held by the backend, the
|
||||
* frontend must either ask for state [MMBackend evaluateExpression:] or wait
|
||||
* for the backend to update [MMVimController processCommandQueue:].
|
||||
* for the backend to update [MMAppController processInput:forIdentifier:].
|
||||
*
|
||||
* The client/server functionality of Vim is handled by the backend. It sets
|
||||
* up a named NSConnection to which other Vim processes can connect.
|
||||
@@ -178,7 +178,6 @@ extern GuiFont gui_mch_retain_font(GuiFont font);
|
||||
[inputQueue release]; inputQueue = nil;
|
||||
[outputQueue release]; outputQueue = nil;
|
||||
[drawData release]; drawData = nil;
|
||||
[frontendProxy release]; frontendProxy = nil;
|
||||
[connection release]; connection = nil;
|
||||
[actionDict release]; actionDict = nil;
|
||||
[sysColorDict release]; sysColorDict = nil;
|
||||
@@ -328,29 +327,29 @@ extern GuiFont gui_mch_retain_font(GuiFont font);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL ok = NO;
|
||||
@try {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(connectionDidDie:)
|
||||
name:NSConnectionDidDieNotification object:connection];
|
||||
|
||||
id proxy = [connection rootProxy];
|
||||
[proxy setProtocolForProxy:@protocol(MMAppProtocol)];
|
||||
appProxy = [[connection rootProxy] retain];
|
||||
[appProxy setProtocolForProxy:@protocol(MMAppProtocol)];
|
||||
|
||||
// NOTE: We do not set any new timeout values for the connection to the
|
||||
// frontend. This means that if the frontend is "stuck" (e.g. in a
|
||||
// modal loop) then any calls to the frontend will block indefinitely
|
||||
// (the default timeouts are huge).
|
||||
|
||||
int pid = [[NSProcessInfo processInfo] processIdentifier];
|
||||
|
||||
frontendProxy = [proxy connectBackend:self pid:pid];
|
||||
if (frontendProxy) {
|
||||
[frontendProxy retain];
|
||||
[frontendProxy setProtocolForProxy:@protocol(MMAppProtocol)];
|
||||
ok = YES;
|
||||
}
|
||||
identifier = [appProxy connectBackend:self pid:pid];
|
||||
return YES;
|
||||
}
|
||||
@catch (NSException *e) {
|
||||
NSLog(@"Exception caught when trying to connect backend: \"%@\"", e);
|
||||
}
|
||||
|
||||
return ok;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)openGUIWindow
|
||||
@@ -506,10 +505,11 @@ extern GuiFont gui_mch_retain_font(GuiFont font);
|
||||
[self insertVimStateMessage];
|
||||
|
||||
@try {
|
||||
[frontendProxy processCommandQueue:outputQueue];
|
||||
//NSLog(@"[%s] Flushing (count=%d)", _cmd, [outputQueue count]);
|
||||
[appProxy processInput:outputQueue forIdentifier:identifier];
|
||||
}
|
||||
@catch (NSException *e) {
|
||||
NSLog(@"Exception caught when processing command queue: \"%@\"", e);
|
||||
NSLog(@"[%s] Exception caught: \"%@\"", _cmd, e);
|
||||
NSLog(@"outputQueue(len:%d)=%@", [outputQueue count]/2,
|
||||
outputQueue);
|
||||
if (![connection isValid]) {
|
||||
@@ -575,7 +575,7 @@ extern GuiFont gui_mch_retain_font(GuiFont font);
|
||||
// Flush the entire queue in case a VimLeave autocommand added
|
||||
// something to the queue.
|
||||
[self queueMessage:CloseWindowMsgID data:nil];
|
||||
[frontendProxy processCommandQueue:outputQueue];
|
||||
[appProxy processInput:outputQueue forIdentifier:identifier];
|
||||
}
|
||||
@catch (NSException *e) {
|
||||
NSLog(@"Exception caught when sending CloseWindowMsgID: \"%@\"", e);
|
||||
@@ -695,9 +695,10 @@ extern GuiFont gui_mch_retain_font(GuiFont font);
|
||||
{
|
||||
char_u *s = NULL;
|
||||
|
||||
@try {
|
||||
[frontendProxy showSavePanelWithAttributes:attr];
|
||||
[self queueMessage:BrowseForFileMsgID properties:attr];
|
||||
[self flushQueue:YES];
|
||||
|
||||
@try {
|
||||
[self waitForDialogReturn];
|
||||
|
||||
if (dialogReturn && [dialogReturn isKindOfClass:[NSString class]])
|
||||
@@ -706,7 +707,7 @@ extern GuiFont gui_mch_retain_font(GuiFont font);
|
||||
[dialogReturn release]; dialogReturn = nil;
|
||||
}
|
||||
@catch (NSException *e) {
|
||||
NSLog(@"Exception caught when showing save panel: \"%@\"", e);
|
||||
NSLog(@"[%s] Exception caught: \"%@\"", _cmd, e);
|
||||
}
|
||||
|
||||
return (char *)s;
|
||||
@@ -734,9 +735,10 @@ extern GuiFont gui_mch_retain_font(GuiFont font);
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
@try {
|
||||
[frontendProxy presentDialogWithAttributes:attr];
|
||||
[self queueMessage:ShowDialogMsgID properties:attr];
|
||||
[self flushQueue:YES];
|
||||
|
||||
@try {
|
||||
[self waitForDialogReturn];
|
||||
|
||||
if (dialogReturn && [dialogReturn isKindOfClass:[NSArray class]]
|
||||
@@ -758,7 +760,7 @@ extern GuiFont gui_mch_retain_font(GuiFont font);
|
||||
[dialogReturn release]; dialogReturn = nil;
|
||||
}
|
||||
@catch (NSException *e) {
|
||||
NSLog(@"Exception caught while showing alert dialog: \"%@\"", e);
|
||||
NSLog(@"[%s] Exception caught: \"%@\"", _cmd, e);
|
||||
}
|
||||
|
||||
return retval;
|
||||
@@ -1060,9 +1062,11 @@ extern GuiFont gui_mch_retain_font(GuiFont font);
|
||||
}
|
||||
} else if (TerminateNowMsgID == msgid) {
|
||||
// Terminate immediately (the frontend is about to quit or this process
|
||||
// was aborted).
|
||||
// was aborted). Don't preserve modified files since the user would
|
||||
// already have been presented with a dialog warning if there were any
|
||||
// modified files when we get here.
|
||||
isTerminating = YES;
|
||||
mch_exit(0);
|
||||
getout(0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1105,16 +1109,6 @@ extern GuiFont gui_mch_retain_font(GuiFont font);
|
||||
[inputQueue addObject:(data ? (id)data : [NSNull null])];
|
||||
}
|
||||
|
||||
- (oneway void)processInputAndData:(in bycopy NSArray *)messages
|
||||
{
|
||||
// This is just a convenience method that allows the frontend to delay
|
||||
// sending messages.
|
||||
int i, count = [messages count];
|
||||
for (i = 1; i < count; i+=2)
|
||||
[self processInput:[[messages objectAtIndex:i-1] intValue]
|
||||
data:[messages objectAtIndex:i]];
|
||||
}
|
||||
|
||||
- (id)evaluateExpressionCocoa:(in bycopy NSString *)expr
|
||||
errorString:(out bycopy NSString **)errstr
|
||||
{
|
||||
@@ -1451,7 +1445,7 @@ extern GuiFont gui_mch_retain_font(GuiFont font);
|
||||
if (waitForAck) {
|
||||
// Never received a connection acknowledgement, so die.
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[frontendProxy release]; frontendProxy = nil;
|
||||
[appProxy release]; appProxy = nil;
|
||||
|
||||
// NOTE: We intentionally do not call mch_exit() since this in turn
|
||||
// will lead to -[MMBackend exit] getting called which we want to
|
||||
@@ -2486,9 +2480,9 @@ extern GuiFont gui_mch_retain_font(GuiFont font);
|
||||
if ([args objectForKey:@"remoteID"]) {
|
||||
// NOTE: We have to delay processing any ODB related arguments since
|
||||
// the file(s) may not be opened until the input buffer is processed.
|
||||
[self performSelectorOnMainThread:@selector(startOdbEditWithArguments:)
|
||||
withObject:args
|
||||
waitUntilDone:NO];
|
||||
[self performSelector:@selector(startOdbEditWithArguments:)
|
||||
withObject:args
|
||||
afterDelay:0];
|
||||
}
|
||||
|
||||
NSString *lineString = [args objectForKey:@"cursorLine"];
|
||||
@@ -2522,9 +2516,7 @@ extern GuiFont gui_mch_retain_font(GuiFont font);
|
||||
|
||||
NSString *searchText = [args objectForKey:@"searchText"];
|
||||
if (searchText) {
|
||||
// TODO: Searching is an exclusive motion, so if the pattern would
|
||||
// match on row 0 column 0 then this pattern will miss that match.
|
||||
[self addInput:[NSString stringWithFormat:@"<C-\\><C-N>gg/\\c%@<CR>",
|
||||
[self addInput:[NSString stringWithFormat:@"<C-\\><C-N>gg/\\c%@/e<CR>",
|
||||
searchText]];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,8 +149,10 @@
|
||||
|
||||
int fuRows = currRows, fuColumns = currColumns;
|
||||
|
||||
// NOTE: Do not use [NSScreen visibleFrame] when determining the screen
|
||||
// size since it compensates for menu and dock.
|
||||
int maxRows, maxColumns;
|
||||
NSSize size = [[self screen] visibleFrame].size;
|
||||
NSSize size = [[self screen] frame].size;
|
||||
[view constrainRows:&maxRows columns:&maxColumns toSize:size];
|
||||
|
||||
// Store current pre-fu vim size
|
||||
|
||||
@@ -52,7 +52,9 @@ static float MMDragAreaSize = 73.0f;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[insertionPointColor release]; insertionPointColor = nil;
|
||||
[markedText release]; markedText = nil;
|
||||
[markedTextAttributes release]; markedTextAttributes = nil;
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
@@ -100,14 +102,19 @@ static float MMDragAreaSize = 73.0f;
|
||||
int flags = [event modifierFlags];
|
||||
if ((flags & NSControlKeyMask) ||
|
||||
((flags & NSAlternateKeyMask) && (flags & NSFunctionKeyMask))) {
|
||||
BOOL unmodIsPrintable = YES;
|
||||
NSString *unmod = [event charactersIgnoringModifiers];
|
||||
if ([unmod length] == 1 && [unmod characterAtIndex:0] <= 0x7f
|
||||
&& [unmod characterAtIndex:0] >= 0x60) {
|
||||
// HACK! Send Ctrl-letter keys (and C-@, C-[, C-\, C-], C-^, C-_)
|
||||
// as normal text to be added to the Vim input buffer. This must
|
||||
// be done in order for the backend to be able to separate e.g.
|
||||
// Ctrl-i and Ctrl-tab.
|
||||
[self insertText:[event characters]];
|
||||
if (unmod && [unmod length] > 0 && [unmod characterAtIndex:0] < 0x20)
|
||||
unmodIsPrintable = NO;
|
||||
|
||||
NSString *chars = [event characters];
|
||||
if ([chars length] == 1 && [chars characterAtIndex:0] < 0x20
|
||||
&& unmodIsPrintable) {
|
||||
// HACK! Send unprintable characters (such as C-@, C-[, C-\, C-],
|
||||
// C-^, C-_) as normal text to be added to the Vim input buffer.
|
||||
// This must be done in order for the backend to be able to
|
||||
// separate e.g. Ctrl-i and Ctrl-tab.
|
||||
[self insertText:chars];
|
||||
} else {
|
||||
[self dispatchKeyEvent:event];
|
||||
}
|
||||
@@ -745,7 +752,7 @@ static float MMDragAreaSize = 73.0f;
|
||||
NSString *chars = [event characters];
|
||||
NSString *unmodchars = [event charactersIgnoringModifiers];
|
||||
unichar c = [chars characterAtIndex:0];
|
||||
unichar imc = [unmodchars characterAtIndex:0];
|
||||
unichar imc = [unmodchars length] > 0 ? [unmodchars characterAtIndex:0] : 0;
|
||||
int len = 0;
|
||||
const char *bytes = 0;
|
||||
int mods = [event modifierFlags];
|
||||
|
||||
@@ -20,14 +20,11 @@
|
||||
|
||||
|
||||
|
||||
@interface MMVimController : NSObject <MMFrontendProtocol>
|
||||
{
|
||||
@interface MMVimController : NSObject {
|
||||
unsigned identifier;
|
||||
BOOL isInitialized;
|
||||
MMWindowController *windowController;
|
||||
id backendProxy;
|
||||
BOOL inProcessCommandQueue;
|
||||
NSMutableArray *sendQueue;
|
||||
NSMutableArray *receiveQueue;
|
||||
NSMenu *mainMenu;
|
||||
NSMutableArray *popupMenuItems;
|
||||
NSToolbar *toolbar;
|
||||
@@ -43,6 +40,7 @@
|
||||
}
|
||||
|
||||
- (id)initWithBackend:(id)backend pid:(int)processIdentifier;
|
||||
- (unsigned)identifier;
|
||||
- (id)backendProxy;
|
||||
- (int)pid;
|
||||
- (void)setServerName:(NSString *)name;
|
||||
@@ -65,7 +63,9 @@
|
||||
timeout:(NSTimeInterval)timeout;
|
||||
- (void)addVimInput:(NSString *)string;
|
||||
- (NSString *)evaluateVimExpression:(NSString *)expr;
|
||||
- (id)evaluateVimExpressionCocoa:(NSString *)expr errorString:(NSString **)errstr;
|
||||
- (id)evaluateVimExpressionCocoa:(NSString *)expr
|
||||
errorString:(NSString **)errstr;
|
||||
- (void)processInputQueue:(NSArray *)queue;
|
||||
#ifdef MM_ENABLE_PLUGINS
|
||||
- (MMPlugInInstanceMediator *)instanceMediator;
|
||||
#endif
|
||||
|
||||
+240
-286
@@ -10,17 +10,20 @@
|
||||
/*
|
||||
* MMVimController
|
||||
*
|
||||
* Coordinates input/output to/from backend. Each MMBackend communicates
|
||||
* directly with a MMVimController.
|
||||
* Coordinates input/output to/from backend. A MMVimController sends input
|
||||
* directly to a MMBackend, but communication from MMBackend to MMVimController
|
||||
* goes via MMAppController so that it can coordinate all incoming distributed
|
||||
* object messages.
|
||||
*
|
||||
* MMVimController does not deal with visual presentation. Essentially it
|
||||
* should be able to run with no window present.
|
||||
*
|
||||
* Output from the backend is received in processCommandQueue:. Input is sent
|
||||
* to the backend via sendMessage:data: or addVimInput:. The latter allows
|
||||
* execution of arbitrary strings in the Vim process, much like the Vim script
|
||||
* function remote_send() does. The messages that may be passed between
|
||||
* frontend and backend are defined in an enum in MacVim.h.
|
||||
* Output from the backend is received in processInputQueue: (this message is
|
||||
* called from MMAppController so it is not a DO call). Input is sent to the
|
||||
* backend via sendMessage:data: or addVimInput:. The latter allows execution
|
||||
* of arbitrary strings in the Vim process, much like the Vim script function
|
||||
* remote_send() does. The messages that may be passed between frontend and
|
||||
* backend are defined in an enum in MacVim.h.
|
||||
*/
|
||||
|
||||
#import "MMAppController.h"
|
||||
@@ -49,9 +52,7 @@ static NSTimeInterval MMBackendProxyRequestTimeout = 0;
|
||||
// Timeout used for setDialogReturn:.
|
||||
static NSTimeInterval MMSetDialogReturnTimeout = 1.0;
|
||||
|
||||
// Maximum number of items in the receiveQueue. (It is hard to predict what
|
||||
// consequences changing this number will have.)
|
||||
static int MMReceiveQueueCap = 100;
|
||||
static unsigned identifierCounter = 1;
|
||||
|
||||
static BOOL isUnsafeMessage(int msgid);
|
||||
|
||||
@@ -65,7 +66,7 @@ static BOOL isUnsafeMessage(int msgid);
|
||||
|
||||
|
||||
@interface MMVimController (Private)
|
||||
- (void)doProcessCommandQueue:(NSArray *)queue;
|
||||
- (void)doProcessInputQueue:(NSArray *)queue;
|
||||
- (void)handleMessage:(int)msgid data:(NSData *)data;
|
||||
- (void)savePanelDidEnd:(NSSavePanel *)panel code:(int)code
|
||||
context:(void *)context;
|
||||
@@ -95,6 +96,8 @@ static BOOL isUnsafeMessage(int msgid);
|
||||
- (void)popupMenuWithAttributes:(NSDictionary *)attrs;
|
||||
- (void)connectionDidDie:(NSNotification *)notification;
|
||||
- (void)scheduleClose;
|
||||
- (void)handleBrowseForFile:(NSDictionary *)attr;
|
||||
- (void)handleShowDialog:(NSDictionary *)attr;
|
||||
@end
|
||||
|
||||
|
||||
@@ -107,11 +110,12 @@ static BOOL isUnsafeMessage(int msgid);
|
||||
if (!(self = [super init]))
|
||||
return nil;
|
||||
|
||||
// TODO: Come up with a better way of creating an identifier.
|
||||
identifier = identifierCounter++;
|
||||
|
||||
windowController =
|
||||
[[MMWindowController alloc] initWithVimController:self];
|
||||
backendProxy = [backend retain];
|
||||
sendQueue = [NSMutableArray new];
|
||||
receiveQueue = [NSMutableArray new];
|
||||
popupMenuItems = [[NSMutableArray alloc] init];
|
||||
toolbarItemDict = [[NSMutableDictionary alloc] init];
|
||||
pid = processIdentifier;
|
||||
@@ -168,8 +172,6 @@ static BOOL isUnsafeMessage(int msgid);
|
||||
|
||||
[serverName release]; serverName = nil;
|
||||
[backendProxy release]; backendProxy = nil;
|
||||
[sendQueue release]; sendQueue = nil;
|
||||
[receiveQueue release]; receiveQueue = nil;
|
||||
|
||||
[toolbarItemDict release]; toolbarItemDict = nil;
|
||||
[toolbar release]; toolbar = nil;
|
||||
@@ -183,6 +185,11 @@ static BOOL isUnsafeMessage(int msgid);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (unsigned)identifier
|
||||
{
|
||||
return identifier;
|
||||
}
|
||||
|
||||
- (MMWindowController *)windowController
|
||||
{
|
||||
return windowController;
|
||||
@@ -252,6 +259,10 @@ static BOOL isUnsafeMessage(int msgid);
|
||||
if (layout < 0 || layout > MMLayoutTabs)
|
||||
layout = MMLayoutTabs;
|
||||
|
||||
BOOL splitVert = [ud boolForKey:MMVerticalSplitKey];
|
||||
if (splitVert && MMLayoutHorizontalSplit == layout)
|
||||
layout = MMLayoutVerticalSplit;
|
||||
|
||||
NSDictionary *args = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSNumber numberWithInt:layout], @"layout",
|
||||
filenames, @"filenames",
|
||||
@@ -317,21 +328,11 @@ static BOOL isUnsafeMessage(int msgid);
|
||||
|
||||
- (void)sendMessage:(int)msgid data:(NSData *)data
|
||||
{
|
||||
//NSLog(@"sendMessage:%s (isInitialized=%d inProcessCommandQueue=%d)",
|
||||
// MessageStrings[msgid], isInitialized, inProcessCommandQueue);
|
||||
//NSLog(@"sendMessage:%s (isInitialized=%d)",
|
||||
// MessageStrings[msgid], isInitialized);
|
||||
|
||||
if (!isInitialized) return;
|
||||
|
||||
if (inProcessCommandQueue) {
|
||||
//NSLog(@"In process command queue; delaying message send.");
|
||||
[sendQueue addObject:[NSNumber numberWithInt:msgid]];
|
||||
if (data)
|
||||
[sendQueue addObject:data];
|
||||
else
|
||||
[sendQueue addObject:[NSNull null]];
|
||||
return;
|
||||
}
|
||||
|
||||
@try {
|
||||
[backendProxy processInput:msgid data:data];
|
||||
}
|
||||
@@ -349,7 +350,7 @@ static BOOL isUnsafeMessage(int msgid);
|
||||
// ball forever. In almost all circumstances sendMessage:data: should be
|
||||
// used instead.
|
||||
|
||||
if (!isInitialized || inProcessCommandQueue)
|
||||
if (!isInitialized)
|
||||
return NO;
|
||||
|
||||
if (timeout < 0) timeout = 0;
|
||||
@@ -396,7 +397,8 @@ static BOOL isUnsafeMessage(int msgid);
|
||||
return eval;
|
||||
}
|
||||
|
||||
- (id)evaluateVimExpressionCocoa:(NSString *)expr errorString:(NSString **)errstr
|
||||
- (id)evaluateVimExpressionCocoa:(NSString *)expr
|
||||
errorString:(NSString **)errstr
|
||||
{
|
||||
id eval = nil;
|
||||
|
||||
@@ -419,6 +421,9 @@ static BOOL isUnsafeMessage(int msgid);
|
||||
{
|
||||
if (!isInitialized) return;
|
||||
|
||||
// Remove any delayed calls made on this object.
|
||||
[NSObject cancelPreviousPerformRequestsWithTarget:self];
|
||||
|
||||
isInitialized = NO;
|
||||
[toolbar setDelegate:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
@@ -427,204 +432,19 @@ static BOOL isUnsafeMessage(int msgid);
|
||||
[windowController cleanup];
|
||||
}
|
||||
|
||||
- (oneway void)showSavePanelWithAttributes:(in bycopy NSDictionary *)attr
|
||||
- (void)processInputQueue:(NSArray *)queue
|
||||
{
|
||||
if (!isInitialized) return;
|
||||
|
||||
BOOL inDefaultMode = [[[NSRunLoop currentRunLoop] currentMode]
|
||||
isEqual:NSDefaultRunLoopMode];
|
||||
if (!inDefaultMode) {
|
||||
// Delay call until run loop is in default mode.
|
||||
[self performSelectorOnMainThread:
|
||||
@selector(showSavePanelWithAttributes:)
|
||||
withObject:attr
|
||||
waitUntilDone:NO
|
||||
modes:[NSArray arrayWithObject:
|
||||
NSDefaultRunLoopMode]];
|
||||
return;
|
||||
// NOTE: This method must not raise any exceptions (see comment in the
|
||||
// calling method).
|
||||
@try {
|
||||
[self doProcessInputQueue:queue];
|
||||
[windowController processInputQueueDidFinish];
|
||||
}
|
||||
|
||||
NSString *dir = [attr objectForKey:@"dir"];
|
||||
BOOL saving = [[attr objectForKey:@"saving"] boolValue];
|
||||
|
||||
if (!dir) {
|
||||
// 'dir == nil' means: set dir to the pwd of the Vim process, or let
|
||||
// open dialog decide (depending on the below user default).
|
||||
BOOL trackPwd = [[NSUserDefaults standardUserDefaults]
|
||||
boolForKey:MMDialogsTrackPwdKey];
|
||||
if (trackPwd)
|
||||
dir = [vimState objectForKey:@"pwd"];
|
||||
@catch (NSException *ex) {
|
||||
NSLog(@"[%s] Caught exception (pid=%d): %@", _cmd, pid, ex);
|
||||
}
|
||||
|
||||
if (saving) {
|
||||
[[NSSavePanel savePanel] beginSheetForDirectory:dir file:nil
|
||||
modalForWindow:[windowController window]
|
||||
modalDelegate:self
|
||||
didEndSelector:@selector(savePanelDidEnd:code:context:)
|
||||
contextInfo:NULL];
|
||||
} else {
|
||||
NSOpenPanel *panel = [NSOpenPanel openPanel];
|
||||
[panel setAllowsMultipleSelection:NO];
|
||||
[panel setAccessoryView:openPanelAccessoryView()];
|
||||
|
||||
[panel beginSheetForDirectory:dir file:nil types:nil
|
||||
modalForWindow:[windowController window]
|
||||
modalDelegate:self
|
||||
didEndSelector:@selector(savePanelDidEnd:code:context:)
|
||||
contextInfo:NULL];
|
||||
}
|
||||
}
|
||||
|
||||
- (oneway void)presentDialogWithAttributes:(in bycopy NSDictionary *)attr
|
||||
{
|
||||
if (!isInitialized) return;
|
||||
|
||||
BOOL inDefaultMode = [[[NSRunLoop currentRunLoop] currentMode]
|
||||
isEqual:NSDefaultRunLoopMode];
|
||||
if (!inDefaultMode) {
|
||||
// Delay call until run loop is in default mode.
|
||||
[self performSelectorOnMainThread:
|
||||
@selector(presentDialogWithAttributes:)
|
||||
withObject:attr
|
||||
waitUntilDone:NO
|
||||
modes:[NSArray arrayWithObject:
|
||||
NSDefaultRunLoopMode]];
|
||||
return;
|
||||
}
|
||||
|
||||
NSArray *buttonTitles = [attr objectForKey:@"buttonTitles"];
|
||||
if (!(buttonTitles && [buttonTitles count])) return;
|
||||
|
||||
int style = [[attr objectForKey:@"alertStyle"] intValue];
|
||||
NSString *message = [attr objectForKey:@"messageText"];
|
||||
NSString *text = [attr objectForKey:@"informativeText"];
|
||||
NSString *textFieldString = [attr objectForKey:@"textFieldString"];
|
||||
MMAlert *alert = [[MMAlert alloc] init];
|
||||
|
||||
// NOTE! This has to be done before setting the informative text.
|
||||
if (textFieldString)
|
||||
[alert setTextFieldString:textFieldString];
|
||||
|
||||
[alert setAlertStyle:style];
|
||||
|
||||
if (message) {
|
||||
[alert setMessageText:message];
|
||||
} else {
|
||||
// If no message text is specified 'Alert' is used, which we don't
|
||||
// want, so set an empty string as message text.
|
||||
[alert setMessageText:@""];
|
||||
}
|
||||
|
||||
if (text) {
|
||||
[alert setInformativeText:text];
|
||||
} else if (textFieldString) {
|
||||
// Make sure there is always room for the input text field.
|
||||
[alert setInformativeText:@""];
|
||||
}
|
||||
|
||||
unsigned i, count = [buttonTitles count];
|
||||
for (i = 0; i < count; ++i) {
|
||||
NSString *title = [buttonTitles objectAtIndex:i];
|
||||
// NOTE: The title of the button may contain the character '&' to
|
||||
// indicate that the following letter should be the key equivalent
|
||||
// associated with the button. Extract this letter and lowercase it.
|
||||
NSString *keyEquivalent = nil;
|
||||
NSRange hotkeyRange = [title rangeOfString:@"&"];
|
||||
if (NSNotFound != hotkeyRange.location) {
|
||||
if ([title length] > NSMaxRange(hotkeyRange)) {
|
||||
NSRange keyEquivRange = NSMakeRange(hotkeyRange.location+1, 1);
|
||||
keyEquivalent = [[title substringWithRange:keyEquivRange]
|
||||
lowercaseString];
|
||||
}
|
||||
|
||||
NSMutableString *string = [NSMutableString stringWithString:title];
|
||||
[string deleteCharactersInRange:hotkeyRange];
|
||||
title = string;
|
||||
}
|
||||
|
||||
[alert addButtonWithTitle:title];
|
||||
|
||||
// Set key equivalent for the button, but only if NSAlert hasn't
|
||||
// already done so. (Check the documentation for
|
||||
// - [NSAlert addButtonWithTitle:] to see what key equivalents are
|
||||
// automatically assigned.)
|
||||
NSButton *btn = [[alert buttons] lastObject];
|
||||
if ([[btn keyEquivalent] length] == 0 && keyEquivalent) {
|
||||
[btn setKeyEquivalent:keyEquivalent];
|
||||
}
|
||||
}
|
||||
|
||||
[alert beginSheetModalForWindow:[windowController window]
|
||||
modalDelegate:self
|
||||
didEndSelector:@selector(alertDidEnd:code:context:)
|
||||
contextInfo:NULL];
|
||||
|
||||
[alert release];
|
||||
}
|
||||
|
||||
- (oneway void)processCommandQueue:(in bycopy NSArray *)queue
|
||||
{
|
||||
if (!isInitialized) return;
|
||||
|
||||
if (inProcessCommandQueue) {
|
||||
// NOTE! If a synchronous DO call is made during
|
||||
// doProcessCommandQueue: below it may happen that this method is
|
||||
// called a second time while the synchronous message is waiting for a
|
||||
// reply (could also happen if doProcessCommandQueue: enters a modal
|
||||
// loop, see comment below). Since this method cannot be considered
|
||||
// reentrant, we queue the input and return immediately.
|
||||
//
|
||||
// If doProcessCommandQueue: enters a modal loop (happens e.g. on
|
||||
// ShowPopupMenuMsgID) then the receiveQueue could grow to become
|
||||
// arbitrarily large because DO calls still get processed. To avoid
|
||||
// this we set a cap on the size of the queue and simply clear it if it
|
||||
// becomes too large. (That is messages will be dropped and hence Vim
|
||||
// and MacVim will at least temporarily be out of sync.)
|
||||
if ([receiveQueue count] >= MMReceiveQueueCap)
|
||||
[receiveQueue removeAllObjects];
|
||||
|
||||
[receiveQueue addObject:queue];
|
||||
return;
|
||||
}
|
||||
|
||||
inProcessCommandQueue = YES;
|
||||
[self doProcessCommandQueue:queue];
|
||||
|
||||
int i;
|
||||
for (i = 0; i < [receiveQueue count]; ++i) {
|
||||
// Note that doProcessCommandQueue: may cause the receiveQueue to grow
|
||||
// or get cleared (due to cap being hit). Make sure to retain the item
|
||||
// to process or it may get released from under us.
|
||||
NSArray *q = [[receiveQueue objectAtIndex:i] retain];
|
||||
[self doProcessCommandQueue:q];
|
||||
[q release];
|
||||
}
|
||||
|
||||
// We assume that the remaining calls make no synchronous DO calls. If
|
||||
// that did happen anyway, the command queue could get processed out of
|
||||
// order.
|
||||
|
||||
// See comment below why this is called here and not later.
|
||||
[windowController processCommandQueueDidFinish];
|
||||
|
||||
// NOTE: Ensure that no calls are made after this "if" clause that may call
|
||||
// sendMessage::. If this happens anyway, such messages will be put on the
|
||||
// send queue and then the queue will not be flushed until the next time
|
||||
// this method is called.
|
||||
if ([sendQueue count] > 0) {
|
||||
@try {
|
||||
[backendProxy processInputAndData:sendQueue];
|
||||
}
|
||||
@catch (NSException *e) {
|
||||
// Connection timed out, just ignore this.
|
||||
//NSLog(@"WARNING! Connection timed out in %s", _cmd);
|
||||
}
|
||||
|
||||
[sendQueue removeAllObjects];
|
||||
}
|
||||
|
||||
[receiveQueue removeAllObjects];
|
||||
inProcessCommandQueue = NO;
|
||||
}
|
||||
|
||||
- (NSToolbarItem *)toolbar:(NSToolbar *)theToolbar
|
||||
@@ -655,67 +475,60 @@ static BOOL isUnsafeMessage(int msgid);
|
||||
|
||||
@implementation MMVimController (Private)
|
||||
|
||||
- (void)doProcessCommandQueue:(NSArray *)queue
|
||||
- (void)doProcessInputQueue:(NSArray *)queue
|
||||
{
|
||||
NSMutableArray *delayQueue = nil;
|
||||
|
||||
@try {
|
||||
unsigned i, count = [queue count];
|
||||
if (count % 2) {
|
||||
NSLog(@"WARNING: Uneven number of components (%d) in command "
|
||||
"queue. Skipping...", count);
|
||||
return;
|
||||
}
|
||||
|
||||
//NSLog(@"======== %s BEGIN ========", _cmd);
|
||||
for (i = 0; i < count; i += 2) {
|
||||
NSData *value = [queue objectAtIndex:i];
|
||||
NSData *data = [queue objectAtIndex:i+1];
|
||||
|
||||
int msgid = *((int*)[value bytes]);
|
||||
//NSLog(@"%s%s", _cmd, MessageStrings[msgid]);
|
||||
|
||||
BOOL inDefaultMode = [[[NSRunLoop currentRunLoop] currentMode]
|
||||
isEqual:NSDefaultRunLoopMode];
|
||||
if (!inDefaultMode && isUnsafeMessage(msgid)) {
|
||||
// NOTE: Because we may be listening to DO messages in "event
|
||||
// tracking mode" we have to take extra care when doing things
|
||||
// like releasing view items (and other Cocoa objects).
|
||||
// Messages that may be potentially "unsafe" are delayed until
|
||||
// the run loop is back to default mode at which time they are
|
||||
// safe to call again.
|
||||
// A problem with this approach is that it is hard to
|
||||
// classify which messages are unsafe. As a rule of thumb, if
|
||||
// a message may release an object used by the Cocoa framework
|
||||
// (e.g. views) then the message should be considered unsafe.
|
||||
// Delaying messages may have undesired side-effects since it
|
||||
// means that messages may not be processed in the order Vim
|
||||
// sent them, so beware.
|
||||
if (!delayQueue)
|
||||
delayQueue = [NSMutableArray array];
|
||||
|
||||
//NSLog(@"Adding unsafe message '%s' to delay queue (mode=%@)",
|
||||
// MessageStrings[msgid],
|
||||
// [[NSRunLoop currentRunLoop] currentMode]);
|
||||
[delayQueue addObject:value];
|
||||
[delayQueue addObject:data];
|
||||
} else {
|
||||
[self handleMessage:msgid data:data];
|
||||
}
|
||||
}
|
||||
//NSLog(@"======== %s END ========", _cmd);
|
||||
unsigned i, count = [queue count];
|
||||
if (count % 2) {
|
||||
NSLog(@"WARNING: Uneven number of components (%d) in command "
|
||||
"queue. Skipping...", count);
|
||||
return;
|
||||
}
|
||||
@catch (NSException *e) {
|
||||
NSLog(@"Exception caught whilst processing command queue: %@", e);
|
||||
|
||||
//NSLog(@"======== %s BEGIN ========", _cmd);
|
||||
for (i = 0; i < count; i += 2) {
|
||||
NSData *value = [queue objectAtIndex:i];
|
||||
NSData *data = [queue objectAtIndex:i+1];
|
||||
|
||||
int msgid = *((int*)[value bytes]);
|
||||
//NSLog(@"%s%s", _cmd, MessageStrings[msgid]);
|
||||
|
||||
BOOL inDefaultMode = [[[NSRunLoop currentRunLoop] currentMode]
|
||||
isEqual:NSDefaultRunLoopMode];
|
||||
if (!inDefaultMode && isUnsafeMessage(msgid)) {
|
||||
// NOTE: Because we may be listening to DO messages in "event
|
||||
// tracking mode" we have to take extra care when doing things
|
||||
// like releasing view items (and other Cocoa objects).
|
||||
// Messages that may be potentially "unsafe" are delayed until
|
||||
// the run loop is back to default mode at which time they are
|
||||
// safe to call again.
|
||||
// A problem with this approach is that it is hard to
|
||||
// classify which messages are unsafe. As a rule of thumb, if
|
||||
// a message may release an object used by the Cocoa framework
|
||||
// (e.g. views) then the message should be considered unsafe.
|
||||
// Delaying messages may have undesired side-effects since it
|
||||
// means that messages may not be processed in the order Vim
|
||||
// sent them, so beware.
|
||||
if (!delayQueue)
|
||||
delayQueue = [NSMutableArray array];
|
||||
|
||||
//NSLog(@"Adding unsafe message '%s' to delay queue (mode=%@)",
|
||||
// MessageStrings[msgid],
|
||||
// [[NSRunLoop currentRunLoop] currentMode]);
|
||||
[delayQueue addObject:value];
|
||||
[delayQueue addObject:data];
|
||||
} else {
|
||||
[self handleMessage:msgid data:data];
|
||||
}
|
||||
}
|
||||
//NSLog(@"======== %s END ========", _cmd);
|
||||
|
||||
if (delayQueue) {
|
||||
//NSLog(@" Flushing delay queue (%d items)", [delayQueue count]/2);
|
||||
[self performSelectorOnMainThread:@selector(processCommandQueue:)
|
||||
withObject:delayQueue
|
||||
waitUntilDone:NO
|
||||
modes:[NSArray arrayWithObject:
|
||||
NSDefaultRunLoopMode]];
|
||||
[self performSelector:@selector(processInputQueue:)
|
||||
withObject:delayQueue
|
||||
afterDelay:0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -911,12 +724,10 @@ static BOOL isUnsafeMessage(int msgid);
|
||||
NSDictionary *attrs = [NSDictionary dictionaryWithData:data];
|
||||
|
||||
// The popup menu enters a modal loop so delay this call so that we
|
||||
// don't block inside processCommandQueue:.
|
||||
[self performSelectorOnMainThread:@selector(popupMenuWithAttributes:)
|
||||
withObject:attrs
|
||||
waitUntilDone:NO
|
||||
modes:[NSArray arrayWithObject:
|
||||
NSDefaultRunLoopMode]];
|
||||
// don't block inside processInputQueue:.
|
||||
[self performSelector:@selector(popupMenuWithAttributes:)
|
||||
withObject:attrs
|
||||
afterDelay:0];
|
||||
} else if (SetMouseShapeMsgID == msgid) {
|
||||
const void *bytes = [data bytes];
|
||||
int shape = *((int*)bytes); bytes += sizeof(int);
|
||||
@@ -977,6 +788,18 @@ static BOOL isUnsafeMessage(int msgid);
|
||||
showWithText:[dict objectForKey:@"text"]
|
||||
flags:[[dict objectForKey:@"flags"] intValue]];
|
||||
}
|
||||
} else if (ActivateKeyScriptID == msgid) {
|
||||
KeyScript(smKeySysScript);
|
||||
} else if (DeactivateKeyScriptID == msgid) {
|
||||
KeyScript(smKeyRoman);
|
||||
} else if (BrowseForFileMsgID == msgid) {
|
||||
NSDictionary *dict = [NSDictionary dictionaryWithData:data];
|
||||
if (dict)
|
||||
[self handleBrowseForFile:dict];
|
||||
} else if (ShowDialogMsgID == msgid) {
|
||||
NSDictionary *dict = [NSDictionary dictionaryWithData:data];
|
||||
if (dict)
|
||||
[self handleShowDialog:dict];
|
||||
// IMPORTANT: When adding a new message, make sure to update
|
||||
// isUnsafeMessage() if necessary!
|
||||
} else {
|
||||
@@ -1424,13 +1247,142 @@ static BOOL isUnsafeMessage(int msgid);
|
||||
// following call ensures that the vim controller is not released until the
|
||||
// run loop is back in the 'default' mode.
|
||||
[[MMAppController sharedInstance]
|
||||
performSelectorOnMainThread:@selector(removeVimController:)
|
||||
withObject:self
|
||||
waitUntilDone:NO
|
||||
modes:[NSArray arrayWithObject:
|
||||
NSDefaultRunLoopMode]];
|
||||
performSelector:@selector(removeVimController:)
|
||||
withObject:self
|
||||
afterDelay:0];
|
||||
}
|
||||
|
||||
// NSSavePanel delegate
|
||||
- (void)panel:(id)sender willExpand:(BOOL)expanding
|
||||
{
|
||||
// Show or hide the "show hidden files" button
|
||||
if (expanding) {
|
||||
[sender setAccessoryView:showHiddenFilesView()];
|
||||
} else {
|
||||
[sender setShowsHiddenFiles:NO];
|
||||
[sender setAccessoryView:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleBrowseForFile:(NSDictionary *)attr
|
||||
{
|
||||
if (!isInitialized) return;
|
||||
|
||||
NSString *dir = [attr objectForKey:@"dir"];
|
||||
BOOL saving = [[attr objectForKey:@"saving"] boolValue];
|
||||
|
||||
if (!dir) {
|
||||
// 'dir == nil' means: set dir to the pwd of the Vim process, or let
|
||||
// open dialog decide (depending on the below user default).
|
||||
BOOL trackPwd = [[NSUserDefaults standardUserDefaults]
|
||||
boolForKey:MMDialogsTrackPwdKey];
|
||||
if (trackPwd)
|
||||
dir = [vimState objectForKey:@"pwd"];
|
||||
}
|
||||
|
||||
if (saving) {
|
||||
NSSavePanel *panel = [NSSavePanel savePanel];
|
||||
|
||||
// The delegate will be notified when the panel is expanded at which
|
||||
// time we may hide/show the "show hidden files" button (this button is
|
||||
// always visible for the open panel since it is always expanded).
|
||||
[panel setDelegate:self];
|
||||
if ([panel isExpanded])
|
||||
[panel setAccessoryView:showHiddenFilesView()];
|
||||
|
||||
[panel beginSheetForDirectory:dir file:nil
|
||||
modalForWindow:[windowController window]
|
||||
modalDelegate:self
|
||||
didEndSelector:@selector(savePanelDidEnd:code:context:)
|
||||
contextInfo:NULL];
|
||||
} else {
|
||||
NSOpenPanel *panel = [NSOpenPanel openPanel];
|
||||
[panel setAllowsMultipleSelection:NO];
|
||||
[panel setAccessoryView:showHiddenFilesView()];
|
||||
|
||||
[panel beginSheetForDirectory:dir file:nil types:nil
|
||||
modalForWindow:[windowController window]
|
||||
modalDelegate:self
|
||||
didEndSelector:@selector(savePanelDidEnd:code:context:)
|
||||
contextInfo:NULL];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleShowDialog:(NSDictionary *)attr
|
||||
{
|
||||
if (!isInitialized) return;
|
||||
|
||||
NSArray *buttonTitles = [attr objectForKey:@"buttonTitles"];
|
||||
if (!(buttonTitles && [buttonTitles count])) return;
|
||||
|
||||
int style = [[attr objectForKey:@"alertStyle"] intValue];
|
||||
NSString *message = [attr objectForKey:@"messageText"];
|
||||
NSString *text = [attr objectForKey:@"informativeText"];
|
||||
NSString *textFieldString = [attr objectForKey:@"textFieldString"];
|
||||
MMAlert *alert = [[MMAlert alloc] init];
|
||||
|
||||
// NOTE! This has to be done before setting the informative text.
|
||||
if (textFieldString)
|
||||
[alert setTextFieldString:textFieldString];
|
||||
|
||||
[alert setAlertStyle:style];
|
||||
|
||||
if (message) {
|
||||
[alert setMessageText:message];
|
||||
} else {
|
||||
// If no message text is specified 'Alert' is used, which we don't
|
||||
// want, so set an empty string as message text.
|
||||
[alert setMessageText:@""];
|
||||
}
|
||||
|
||||
if (text) {
|
||||
[alert setInformativeText:text];
|
||||
} else if (textFieldString) {
|
||||
// Make sure there is always room for the input text field.
|
||||
[alert setInformativeText:@""];
|
||||
}
|
||||
|
||||
unsigned i, count = [buttonTitles count];
|
||||
for (i = 0; i < count; ++i) {
|
||||
NSString *title = [buttonTitles objectAtIndex:i];
|
||||
// NOTE: The title of the button may contain the character '&' to
|
||||
// indicate that the following letter should be the key equivalent
|
||||
// associated with the button. Extract this letter and lowercase it.
|
||||
NSString *keyEquivalent = nil;
|
||||
NSRange hotkeyRange = [title rangeOfString:@"&"];
|
||||
if (NSNotFound != hotkeyRange.location) {
|
||||
if ([title length] > NSMaxRange(hotkeyRange)) {
|
||||
NSRange keyEquivRange = NSMakeRange(hotkeyRange.location+1, 1);
|
||||
keyEquivalent = [[title substringWithRange:keyEquivRange]
|
||||
lowercaseString];
|
||||
}
|
||||
|
||||
NSMutableString *string = [NSMutableString stringWithString:title];
|
||||
[string deleteCharactersInRange:hotkeyRange];
|
||||
title = string;
|
||||
}
|
||||
|
||||
[alert addButtonWithTitle:title];
|
||||
|
||||
// Set key equivalent for the button, but only if NSAlert hasn't
|
||||
// already done so. (Check the documentation for
|
||||
// - [NSAlert addButtonWithTitle:] to see what key equivalents are
|
||||
// automatically assigned.)
|
||||
NSButton *btn = [[alert buttons] lastObject];
|
||||
if ([[btn keyEquivalent] length] == 0 && keyEquivalent) {
|
||||
[btn setKeyEquivalent:keyEquivalent];
|
||||
}
|
||||
}
|
||||
|
||||
[alert beginSheetModalForWindow:[windowController window]
|
||||
modalDelegate:self
|
||||
didEndSelector:@selector(alertDidEnd:code:context:)
|
||||
contextInfo:NULL];
|
||||
|
||||
[alert release];
|
||||
}
|
||||
|
||||
|
||||
@end // MMVimController (Private)
|
||||
|
||||
|
||||
@@ -1521,6 +1473,8 @@ isUnsafeMessage(int msgid)
|
||||
EnterFullscreenMsgID, // Modifies delegate of window controller
|
||||
LeaveFullscreenMsgID, // Modifies delegate of window controller
|
||||
CloseWindowMsgID, // See note below
|
||||
BrowseForFileMsgID, // Enters modal loop
|
||||
ShowDialogMsgID, // Enters modal loop
|
||||
};
|
||||
|
||||
// NOTE about CloseWindowMsgID: If this arrives at the same time as say
|
||||
|
||||
+11
-1
@@ -142,8 +142,18 @@
|
||||
|
||||
- (IBAction)zoom:(id)sender
|
||||
{
|
||||
NSScreen *screen = [self screen];
|
||||
if (!screen) {
|
||||
NSLog(@"[%s] WINDOW NOT ON SCREEN, zoom to main screen", _cmd);
|
||||
screen = [NSScreen mainScreen];
|
||||
if (!screen) {
|
||||
NSLog(@"[%s] NO MAIN SCREEN, abort zoom", _cmd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NSRect frame = [self frame];
|
||||
NSRect defaultFrame = [[self screen] visibleFrame];
|
||||
NSRect defaultFrame = [screen visibleFrame];
|
||||
defaultFrame = [[self delegate] windowWillUseStandardFrame:self
|
||||
defaultFrame:defaultFrame];
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
MMVimView *vimView;
|
||||
BOOL setupDone;
|
||||
BOOL shouldResizeVimView;
|
||||
int updateToolbarFlag;
|
||||
BOOL keepOnScreen;
|
||||
BOOL fullscreenEnabled;
|
||||
NSString *windowAutosaveKey;
|
||||
@@ -54,7 +55,7 @@
|
||||
- (void)setDefaultColorsBackground:(NSColor *)back foreground:(NSColor *)fore;
|
||||
- (void)setFont:(NSFont *)font;
|
||||
- (void)setWideFont:(NSFont *)font;
|
||||
- (void)processCommandQueueDidFinish;
|
||||
- (void)processInputQueueDidFinish;
|
||||
- (void)showTabBar:(BOOL)on;
|
||||
- (void)showToolbar:(BOOL)on size:(int)size mode:(int)mode;
|
||||
- (void)setMouseShape:(int)shape;
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
- (BOOL)askBackendForStarRegister:(NSPasteboard *)pb;
|
||||
- (void)hideTablineSeparator:(BOOL)hide;
|
||||
- (void)doFindNext:(BOOL)next;
|
||||
- (void)updateToolbar;
|
||||
@end
|
||||
|
||||
|
||||
@@ -307,7 +308,7 @@
|
||||
// NOTE: The only place where the (rows,columns) of the vim view are
|
||||
// modified is here and when entering/leaving full-screen. Setting these
|
||||
// values have no immediate effect, the actual resizing of the view is done
|
||||
// in processCommandQueueDidFinish.
|
||||
// in processInputQueueDidFinish.
|
||||
//
|
||||
// The 'live' flag indicates that this resize originated from a live
|
||||
// resize; it may very well happen that the view is no longer in live
|
||||
@@ -418,16 +419,16 @@
|
||||
[[vimView textView] setWideFont:font];
|
||||
}
|
||||
|
||||
- (void)processCommandQueueDidFinish
|
||||
- (void)processInputQueueDidFinish
|
||||
{
|
||||
// IMPORTANT! No synchronous DO calls are allowed in this method. They
|
||||
// may cause the command queue to get processed out of order.
|
||||
|
||||
// NOTE: Resizing is delayed until after all commands have been processed
|
||||
// since it often happens that more than one command will cause a resize.
|
||||
// If we were to immediately resize then the vim view size would jitter
|
||||
// (e.g. hiding/showing scrollbars often happens several time in one
|
||||
// update).
|
||||
// Also delay toggling the toolbar until after scrollbars otherwise
|
||||
// problems arise when showing toolbar and scrollbar at the same time, i.e.
|
||||
// on "set go+=rT".
|
||||
|
||||
if (shouldResizeVimView) {
|
||||
shouldResizeVimView = NO;
|
||||
@@ -448,6 +449,9 @@
|
||||
|
||||
keepOnScreen = NO;
|
||||
}
|
||||
|
||||
if (updateToolbarFlag != 0)
|
||||
[self updateToolbar];
|
||||
}
|
||||
|
||||
- (void)showTabBar:(BOOL)on
|
||||
@@ -481,21 +485,17 @@
|
||||
|
||||
[toolbar setSizeMode:size];
|
||||
[toolbar setDisplayMode:mode];
|
||||
[toolbar setVisible:on];
|
||||
|
||||
if (([decoratedWindow styleMask] & NSTexturedBackgroundWindowMask) == 0) {
|
||||
if (!on) {
|
||||
[self hideTablineSeparator:YES];
|
||||
} else {
|
||||
[self hideTablineSeparator:![[vimView tabBarControl] isHidden]];
|
||||
}
|
||||
} else {
|
||||
// Textured windows don't have a line below there title bar, so we
|
||||
// need the separator in this case as well. In fact, the only case
|
||||
// where we don't need the separator is when the tab bar control
|
||||
// is visible (because it brings its own separator).
|
||||
[self hideTablineSeparator:![[vimView tabBarControl] isHidden]];
|
||||
}
|
||||
// Positive flag shows toolbar, negative hides it.
|
||||
updateToolbarFlag = on ? 1 : -1;
|
||||
|
||||
// NOTE: If the window is not visible we must toggle the toolbar
|
||||
// immediately, otherwise "set go-=T" in .gvimrc will lead to the toolbar
|
||||
// showing its hide animation every time a new window is opened. (See
|
||||
// processInputQueueDidFinish for the reason why we need to delay toggling
|
||||
// the toolbar when the window is visible.)
|
||||
if (![decoratedWindow isVisible])
|
||||
[self updateToolbar];
|
||||
}
|
||||
|
||||
- (void)setMouseShape:(int)shape
|
||||
@@ -757,7 +757,19 @@
|
||||
|
||||
- (void)windowDidMove:(NSNotification *)notification
|
||||
{
|
||||
if (setupDone && windowAutosaveKey) {
|
||||
if (!setupDone)
|
||||
return;
|
||||
|
||||
if (fullscreenEnabled) {
|
||||
// HACK! The full-screen is not supposed to be able to be moved. If we
|
||||
// do get here while in full-screen something unexpected happened (e.g.
|
||||
// the full-screen window was on an external display that got
|
||||
// unplugged) and we handle this situation by leaving full-screen.
|
||||
[self leaveFullscreen];
|
||||
return;
|
||||
}
|
||||
|
||||
if (windowAutosaveKey) {
|
||||
NSRect frame = [decoratedWindow frame];
|
||||
NSPoint topLeft = { frame.origin.x, NSMaxY(frame) };
|
||||
NSString *topLeftString = NSStringFromPoint(topLeft);
|
||||
@@ -774,7 +786,11 @@
|
||||
// size in updateResizeConstraints since the screen's visible frame may
|
||||
// change at any time (dock could move, resolution could change, window
|
||||
// could be moved to another screen, ...).
|
||||
if (![win screen])
|
||||
return proposedFrameSize;
|
||||
|
||||
// NOTE: Not called in full-screen mode so use "visibleFrame" instead of
|
||||
// "frame".
|
||||
NSRect maxFrame = [self constrainFrame:[[win screen] visibleFrame]];
|
||||
|
||||
if (proposedFrameSize.width > maxFrame.size.width)
|
||||
@@ -891,24 +907,28 @@
|
||||
|
||||
NSRect newFrame = [decoratedWindow frameRectForContentRect:contentRect];
|
||||
|
||||
// Ensure that the window fits inside the visible part of the screen.
|
||||
NSRect maxFrame = [[decoratedWindow screen] visibleFrame];
|
||||
maxFrame = [self constrainFrame:maxFrame];
|
||||
if ([decoratedWindow screen]) {
|
||||
// Ensure that the window fits inside the visible part of the screen.
|
||||
// NOTE: Not called in full-screen mode so use "visibleFrame' instead
|
||||
// of "frame".
|
||||
NSRect maxFrame = [[decoratedWindow screen] visibleFrame];
|
||||
maxFrame = [self constrainFrame:maxFrame];
|
||||
|
||||
if (newFrame.size.width > maxFrame.size.width) {
|
||||
newFrame.size.width = maxFrame.size.width;
|
||||
newFrame.origin.x = maxFrame.origin.x;
|
||||
}
|
||||
if (newFrame.size.height > maxFrame.size.height) {
|
||||
newFrame.size.height = maxFrame.size.height;
|
||||
newFrame.origin.y = maxFrame.origin.y;
|
||||
}
|
||||
|
||||
if (onScreen) {
|
||||
if (newFrame.origin.y < maxFrame.origin.y)
|
||||
if (newFrame.size.width > maxFrame.size.width) {
|
||||
newFrame.size.width = maxFrame.size.width;
|
||||
newFrame.origin.x = maxFrame.origin.x;
|
||||
}
|
||||
if (newFrame.size.height > maxFrame.size.height) {
|
||||
newFrame.size.height = maxFrame.size.height;
|
||||
newFrame.origin.y = maxFrame.origin.y;
|
||||
if (NSMaxX(newFrame) > NSMaxX(maxFrame))
|
||||
newFrame.origin.x = NSMaxX(maxFrame) - newFrame.size.width;
|
||||
}
|
||||
|
||||
if (onScreen) {
|
||||
if (newFrame.origin.y < maxFrame.origin.y)
|
||||
newFrame.origin.y = maxFrame.origin.y;
|
||||
if (NSMaxX(newFrame) > NSMaxX(maxFrame))
|
||||
newFrame.origin.x = NSMaxX(maxFrame) - newFrame.size.width;
|
||||
}
|
||||
}
|
||||
|
||||
[decoratedWindow setFrame:newFrame display:YES];
|
||||
@@ -917,7 +937,15 @@
|
||||
- (NSSize)constrainContentSizeToScreenSize:(NSSize)contentSize
|
||||
{
|
||||
NSWindow *win = [self window];
|
||||
NSRect rect = [win contentRectForFrameRect:[[win screen] visibleFrame]];
|
||||
if (![win screen])
|
||||
return contentSize;
|
||||
|
||||
// NOTE: This may be called in both windowed and full-screen mode. The
|
||||
// "visibleFrame" method does not overlap menu and dock so should not be
|
||||
// used in full-screen.
|
||||
NSRect screenRect = fullscreenEnabled ? [[win screen] frame]
|
||||
: [[win screen] visibleFrame];
|
||||
NSRect rect = [win contentRectForFrameRect:screenRect];
|
||||
|
||||
if (contentSize.height > rect.size.height)
|
||||
contentSize.height = rect.size.height;
|
||||
@@ -1025,4 +1053,30 @@
|
||||
[vimController addVimInput:input];
|
||||
}
|
||||
|
||||
- (void)updateToolbar
|
||||
{
|
||||
NSToolbar *toolbar = [decoratedWindow toolbar];
|
||||
if (nil == toolbar || 0 == updateToolbarFlag) return;
|
||||
|
||||
// Positive flag shows toolbar, negative hides it.
|
||||
BOOL on = updateToolbarFlag > 0 ? YES : NO;
|
||||
[toolbar setVisible:on];
|
||||
|
||||
if (([decoratedWindow styleMask] & NSTexturedBackgroundWindowMask) == 0) {
|
||||
if (!on) {
|
||||
[self hideTablineSeparator:YES];
|
||||
} else {
|
||||
[self hideTablineSeparator:![[vimView tabBarControl] isHidden]];
|
||||
}
|
||||
} else {
|
||||
// Textured windows don't have a line below there title bar, so we
|
||||
// need the separator in this case as well. In fact, the only case
|
||||
// where we don't need the separator is when the tab bar control
|
||||
// is visible (because it brings its own separator).
|
||||
[self hideTablineSeparator:![[vimView tabBarControl] isHidden]];
|
||||
}
|
||||
|
||||
updateToolbarFlag = 0;
|
||||
}
|
||||
|
||||
@end // MMWindowController (Private)
|
||||
|
||||
+24
-20
@@ -33,7 +33,6 @@
|
||||
//
|
||||
@protocol MMBackendProtocol
|
||||
- (oneway void)processInput:(int)msgid data:(in bycopy NSData *)data;
|
||||
- (oneway void)processInputAndData:(in bycopy NSArray *)messages;
|
||||
- (oneway void)setDialogReturn:(in bycopy id)obj;
|
||||
- (NSString *)evaluateExpression:(in bycopy NSString *)expr;
|
||||
- (id)evaluateExpressionCocoa:(in bycopy NSString *)expr
|
||||
@@ -42,30 +41,23 @@
|
||||
- (oneway void)acknowledgeConnection;
|
||||
@end
|
||||
|
||||
//
|
||||
// This is the protocol MMVimController implements.
|
||||
//
|
||||
// Be very careful if you want to add methods to this protocol. Since DO
|
||||
// messages may arrive while Cocoa is in the middle of processing some other
|
||||
// message be sure to consider reentrancy issues. Look at processCommandQueue:
|
||||
// to see an example of how to deal with this.
|
||||
//
|
||||
@protocol MMFrontendProtocol
|
||||
- (oneway void)processCommandQueue:(in bycopy NSArray *)queue;
|
||||
- (oneway void)showSavePanelWithAttributes:(in bycopy NSDictionary *)attr;
|
||||
- (oneway void)presentDialogWithAttributes:(in bycopy NSDictionary *)attr;
|
||||
@end
|
||||
|
||||
|
||||
//
|
||||
// This is the protocol MMAppController implements.
|
||||
//
|
||||
// It handles connections between MacVim and Vim.
|
||||
// It handles connections between MacVim and Vim and communication from Vim to
|
||||
// MacVim.
|
||||
//
|
||||
// Do not add methods to this interface without a _very_ good reason (if
|
||||
// possible, instead add a new message to the *MsgID enum below and pass it via
|
||||
// processInput:forIdentifier). Methods should not modify the state directly
|
||||
// but should instead delay any potential modifications (see
|
||||
// connectBackend:pid: and processInput:forIdentifier:).
|
||||
//
|
||||
@protocol MMAppProtocol
|
||||
- (byref id <MMFrontendProtocol>)
|
||||
connectBackend:(byref in id <MMBackendProtocol>)backend
|
||||
pid:(int)pid;
|
||||
- (unsigned)connectBackend:(byref in id <MMBackendProtocol>)proxy pid:(int)pid;
|
||||
- (oneway void)processInput:(in bycopy NSArray *)queue
|
||||
forIdentifier:(unsigned)identifier;
|
||||
- (NSArray *)serverList;
|
||||
@end
|
||||
|
||||
@@ -109,7 +101,7 @@
|
||||
extern char *MessageStrings[];
|
||||
|
||||
enum {
|
||||
OpenWindowMsgID = 1,
|
||||
OpenWindowMsgID = 1, // NOTE: FIRST IN ENUM MUST BE 1
|
||||
InsertTextMsgID,
|
||||
KeyDownMsgID,
|
||||
CmdKeyMsgID,
|
||||
@@ -177,6 +169,11 @@ enum {
|
||||
SetFullscreenColorMsgID,
|
||||
ShowFindReplaceDialogMsgID,
|
||||
FindReplaceMsgID,
|
||||
ActivateKeyScriptID,
|
||||
DeactivateKeyScriptID,
|
||||
BrowseForFileMsgID,
|
||||
ShowDialogMsgID,
|
||||
LastMsgID // NOTE: MUST BE LAST MESSAGE IN ENUM!
|
||||
};
|
||||
|
||||
|
||||
@@ -215,6 +212,13 @@ enum {
|
||||
MMTabInfoCount
|
||||
};
|
||||
|
||||
|
||||
// Create a string holding the labels of all messages in message queue for
|
||||
// debugging purposes (condense some messages since there may typically be LOTS
|
||||
// of them on a queue).
|
||||
NSString *debugStringForMessageQueue(NSArray *queue);
|
||||
|
||||
|
||||
// Argument used to stop MacVim from opening an empty window on startup
|
||||
// (techincally this is a user default but should not be used as such).
|
||||
extern NSString *MMNoWindowKey;
|
||||
|
||||
+34
-1
@@ -29,7 +29,7 @@ char *MessageStrings[] =
|
||||
"ShowTabBarMsgID",
|
||||
"HideTabBarMsgID",
|
||||
"SetTextRowsMsgID",
|
||||
"SetTextColumsMsgID",
|
||||
"SetTextColumnsMsgID",
|
||||
"SetTextDimensionsMsgID",
|
||||
"LiveResizeMsgID",
|
||||
"SetTextDimensionsReplyMsgID",
|
||||
@@ -84,6 +84,11 @@ char *MessageStrings[] =
|
||||
"SetFullscreenColorMsgID",
|
||||
"ShowFindReplaceDialogMsgID",
|
||||
"FindReplaceMsgID",
|
||||
"ActivateKeyScriptID",
|
||||
"DeactivateKeyScriptID",
|
||||
"BrowseForFileMsgID",
|
||||
"ShowDialogMsgID",
|
||||
"END OF MESSAGE IDs" // NOTE: Must be last!
|
||||
};
|
||||
|
||||
|
||||
@@ -98,6 +103,34 @@ NSString *VimPBoardType = @"VimPBoardType";
|
||||
|
||||
|
||||
|
||||
// Create a string holding the labels of all messages in message queue for
|
||||
// debugging purposes (condense some messages since there may typically be LOTS
|
||||
// of them on a queue).
|
||||
NSString *
|
||||
debugStringForMessageQueue(NSArray *queue)
|
||||
{
|
||||
NSMutableString *s = [NSMutableString new];
|
||||
unsigned i, count = [queue count];
|
||||
int item = 0, menu = 0, enable = 0;
|
||||
for (i = 0; i < count; i += 2) {
|
||||
NSData *value = [queue objectAtIndex:i];
|
||||
int msgid = *((int*)[value bytes]);
|
||||
if (msgid < 1 || msgid >= LastMsgID)
|
||||
continue;
|
||||
if (msgid == AddMenuItemMsgID) ++item;
|
||||
else if (msgid == AddMenuMsgID) ++menu;
|
||||
else if (msgid == EnableMenuItemMsgID) ++enable;
|
||||
else [s appendFormat:@"%s ", MessageStrings[msgid]];
|
||||
}
|
||||
if (item > 0) [s appendFormat:@"AddMenuItemMsgID(%d) ", item];
|
||||
if (menu > 0) [s appendFormat:@"AddMenuMsgID(%d) ", menu];
|
||||
if (enable > 0) [s appendFormat:@"EnableMenuItemMsgID(%d) ", enable];
|
||||
|
||||
return [s autorelease];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@implementation NSString (MMExtras)
|
||||
|
||||
|
||||
@@ -737,7 +737,7 @@
|
||||
i386,
|
||||
);
|
||||
COPY_PHASE_STRIP = YES;
|
||||
CURRENT_PROJECT_VERSION = 41;
|
||||
CURRENT_PROJECT_VERSION = 45;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(FRAMEWORK_SEARCH_PATHS_QUOTED_1)",
|
||||
@@ -778,7 +778,7 @@
|
||||
buildSettings = {
|
||||
ARCHS = "$(NATIVE_ARCH)";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 41;
|
||||
CURRENT_PROJECT_VERSION = 45;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(FRAMEWORK_SEARCH_PATHS_QUOTED_1)",
|
||||
@@ -810,7 +810,7 @@
|
||||
buildSettings = {
|
||||
ARCHS = "$(NATIVE_ARCH)";
|
||||
COPY_PHASE_STRIP = YES;
|
||||
CURRENT_PROJECT_VERSION = 41;
|
||||
CURRENT_PROJECT_VERSION = 45;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(FRAMEWORK_SEARCH_PATHS_QUOTED_1)",
|
||||
|
||||
@@ -95,7 +95,7 @@ enum {
|
||||
@end
|
||||
|
||||
|
||||
@interface NSOpenPanel (MMExtras)
|
||||
@interface NSSavePanel (MMExtras)
|
||||
- (void)hiddenFilesButtonToggled:(id)sender;
|
||||
- (void)setShowsHiddenFiles:(BOOL)show;
|
||||
@end
|
||||
@@ -130,7 +130,8 @@ enum {
|
||||
|
||||
|
||||
|
||||
// Create a view to be used as accessory for open panel. This function assumes
|
||||
// ownership of the view so do not release it.
|
||||
NSView *openPanelAccessoryView();
|
||||
// Create a view with a "show hidden files" button to be used as accessory for
|
||||
// open/save panels. This function assumes ownership of the view so do not
|
||||
// release it.
|
||||
NSView *showHiddenFilesView();
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ NSString *MMLoadDefaultFontKey = @"MMLoadDefaultFont";
|
||||
|
||||
|
||||
|
||||
@implementation NSOpenPanel (MMExtras)
|
||||
@implementation NSSavePanel (MMExtras)
|
||||
|
||||
- (void)hiddenFilesButtonToggled:(id)sender
|
||||
{
|
||||
@@ -122,7 +122,7 @@ NSString *MMLoadDefaultFontKey = @"MMLoadDefaultFont";
|
||||
[invocation invoke];
|
||||
}
|
||||
|
||||
@end // NSOpenPanel (MMExtras)
|
||||
@end // NSSavePanel (MMExtras)
|
||||
|
||||
|
||||
|
||||
@@ -263,7 +263,7 @@ NSString *MMLoadDefaultFontKey = @"MMLoadDefaultFont";
|
||||
|
||||
|
||||
NSView *
|
||||
openPanelAccessoryView()
|
||||
showHiddenFilesView()
|
||||
{
|
||||
// Return a new button object for each NSOpenPanel -- several of them
|
||||
// could be displayed at once.
|
||||
@@ -272,13 +272,13 @@ openPanelAccessoryView()
|
||||
NSButton *button = [[[NSButton alloc]
|
||||
initWithFrame:NSMakeRect(0, 0, 140, 18)] autorelease];
|
||||
[button setTitle:
|
||||
NSLocalizedString(@"Show Hidden Files", @"Open File Dialog")];
|
||||
NSLocalizedString(@"Show Hidden Files", @"Show Hidden Files Checkbox")];
|
||||
[button setButtonType:NSSwitchButton];
|
||||
|
||||
[button setTarget:nil];
|
||||
[button setAction:@selector(hiddenFilesButtonToggled:)];
|
||||
|
||||
// use the regular control size (checkbox is a bit smaller without this)
|
||||
// Use the regular control size (checkbox is a bit smaller without this)
|
||||
NSControlSize buttonSize = NSRegularControlSize;
|
||||
float fontSize = [NSFont systemFontSizeForControlSize:buttonSize];
|
||||
NSCell *theCell = [button cell];
|
||||
|
||||
+17
-18
@@ -20,16 +20,16 @@ is very easy to pick up if you know C and some object oriented programming.)
|
||||
Each editor window in MacVim runs its own Vim process (but there is always
|
||||
only one MacVim process). Communication between MacVim and a Vim process is
|
||||
done using Distributed Objects (DO). Each Vim process is represented by a
|
||||
backend object (MMBackend) and it communicates with a frontend object in the
|
||||
Vim process (MMVimController). The interface between the backend and frontend
|
||||
backend object (MMBackend) and it communicates with the frontend object in the
|
||||
Vim process (MMAppController). The interface between the backend and frontend
|
||||
is defined in MacVim.h.
|
||||
|
||||
The frontend sends input to the backend by calling
|
||||
-[MMBackend processInput:data:]. The backend queues output on a command queue
|
||||
and sends it to the frontend at opportune times by calling
|
||||
-[MMVimController processCommandQueue:]. These are both asynchronous calls so
|
||||
MacVim can keep drawing and receiving input while Vim is working away, thus
|
||||
always keeping the user interface responsive.
|
||||
-[MMAppController processInput:forIdentifier:]. These are both asynchronous
|
||||
calls so MacVim can keep drawing and receiving input while Vim is working away,
|
||||
thus always keeping the user interface responsive.
|
||||
|
||||
The state of each editor window is kept entirely in the Vim process. MacVim
|
||||
should remain "ignorant" in the sense that it knows nothing of the actual
|
||||
@@ -46,7 +46,7 @@ to MacVim inside -[MMBackend queueVimStateMessage].
|
||||
|
||||
Vim:
|
||||
|
||||
Hooks from within Vim are implmented in gui_macvim.m, the name of such
|
||||
Hooks from within Vim are implemented in gui_macvim.m, the name of such
|
||||
functions usually start with "gui_mch_" and they should simply put a message
|
||||
on the output queue, by calling queueMessage:properties: on the singleton
|
||||
MMBackend object [MMBackend sharedInstance] (see e.g. gui_mch_destroy_menu()).
|
||||
@@ -63,7 +63,7 @@ for some reason fails to update the run loop then incoming DO calls will not
|
||||
be processed and for this reason it is best to avoid making synchronous DO
|
||||
calls from MacVim. (If synchronous calls must be made then it is important to
|
||||
set proper timeouts so that MacVim doesn't "hang", see
|
||||
-[MMVimConroller sendMessageNow:::] to see how this can be done.)
|
||||
-[MMVimController sendMessageNow:::] to see how this can be done.)
|
||||
|
||||
|
||||
MacVim:
|
||||
@@ -71,16 +71,15 @@ MacVim:
|
||||
The main nib of MacVim.app is MainMenu.nib which contains the default menu and
|
||||
an instance of MMAppController, which is connected as the delegate of
|
||||
NSApplication. That means, when MacVim starts it will load this nib file and
|
||||
automatically create an instance of the MMAppController singleton.
|
||||
automatically create an instance of the MMAppController singleton. All
|
||||
incoming distributed object calls go via MMAppController.
|
||||
|
||||
A new editor window is opened by calling
|
||||
-[MMAppController launchVimProcessWithArguments:]. This functions starts a
|
||||
new Vim process (by executing the Vim binary). The Vim process lets MacVim
|
||||
know when it has launched by calling -[MMAppController connectBackend:pid:]
|
||||
and MacVim responds to this message by creating a new frontend object
|
||||
(MMVimController) and returns a proxy to this object back to the Vim process.
|
||||
From this point onward the Vim process communicates directly with the
|
||||
MMVimController.
|
||||
and MacVim responds to this message by creating a new vim controller and
|
||||
returns an identifier for this object back to the Vim process.
|
||||
|
||||
The MMVimController represents the frontend of a Vim process inside MacVim.
|
||||
It coordinates all communication with the Vim process and delegates output
|
||||
@@ -88,7 +87,7 @@ that affects visual presentation to a MMWindowController object. Read the
|
||||
Cocoa documentation on the responsibilities of a window controller.
|
||||
|
||||
Input (keyboard & mouse) handling and drawing is handled by a helper object
|
||||
(MMTextViewHelper) to the current text view (MMTextView, MMAtsuiTextView).
|
||||
(MMTextViewHelper) to the current text view (MMTextView, MMAtsuiTextView, ...).
|
||||
|
||||
|
||||
Distributed Object dangers:
|
||||
@@ -106,7 +105,7 @@ message may arrive.
|
||||
the menu flashes briefly. During this "flash" a modal loop is entered.
|
||||
|
||||
Item 1 can cause a problem if MacVim sends a synchronous message and before a
|
||||
reply reacheds MacVim another message is received. From the source code it
|
||||
reply reaches MacVim another message is received. From the source code it
|
||||
looks like the synchronous message blocks but in fact the other message is
|
||||
executed during this "block". If the other message changes state radically
|
||||
something may go wrong after the synchronous DO message returns.
|
||||
@@ -117,8 +116,8 @@ which may be even more puzzling.
|
||||
One way to alleviate these problems is to ensure a DO message isn't entered
|
||||
twice by setting a boolean at the beginning of the message and clearing it
|
||||
afterwards. If the boolean is already set when entering the call must somehow
|
||||
be delayed. See -[MMVimController processCommandQueue:] for a concrete
|
||||
example.
|
||||
be delayed. See processInput:forIdentifier: and processInputQueues: inside
|
||||
MMAppController for a concrete example.
|
||||
|
||||
Another danger is that we must take care when releasing objects that Cocoa may
|
||||
be using. See -[MMVimController connectionDidDie:] how MacVim releases
|
||||
@@ -133,7 +132,7 @@ what they contain:
|
||||
MMAppController.* Everything related to running the application
|
||||
MMBackend.* Object representing a Vim process in backend
|
||||
MMTextView.* Handles input and drawing
|
||||
MMVimController.* Object representing a Vim Process in frontend
|
||||
MMVimController.* Object representing a Vim process in frontend
|
||||
MMVimView.* Cocoa view object
|
||||
MMWindowController.* Coordinates visual presentation
|
||||
MacVim.* Code shared between MacVim and Vim
|
||||
@@ -161,4 +160,4 @@ The application bundle can be found inside "src/MacVim/build/Release".
|
||||
|
||||
|
||||
Bjorn Winckler <bjorn.winckler@gmail.com>
|
||||
November 22, 2008
|
||||
April 5, 2009
|
||||
|
||||
+10
-23
@@ -25,7 +25,6 @@ static NSString *MMDefaultFontName = @"DejaVu Sans Mono";
|
||||
static int MMDefaultFontSize = 12;
|
||||
static int MMMinFontSize = 6;
|
||||
static int MMMaxFontSize = 100;
|
||||
static BOOL gui_mch_init_has_finished = NO;
|
||||
|
||||
|
||||
static GuiFont gui_macvim_font_with_name(char_u *name);
|
||||
@@ -99,15 +98,6 @@ gui_mch_init(void)
|
||||
{
|
||||
//NSLog(@"gui_mch_init()");
|
||||
|
||||
// NOTE! Because OS X has to exec after fork we effectively end up doing
|
||||
// the initialization twice (because this function is called before the
|
||||
// fork). To avoid all this extra work we check if Vim is about to fork,
|
||||
// and if so do nothing for now.
|
||||
//
|
||||
// TODO: Is this check 100% foolproof?
|
||||
if (gui.dofork && (vim_strchr(p_go, GO_FORG) == NULL))
|
||||
return OK;
|
||||
|
||||
if (![[MMBackend sharedInstance] checkin]) {
|
||||
// TODO: Kill the process if there is no terminal to fall back on,
|
||||
// otherwise the process will run outputting to the console.
|
||||
@@ -140,8 +130,6 @@ gui_mch_init(void)
|
||||
// in [g]vimrc.
|
||||
gui_mch_adjust_charheight();
|
||||
|
||||
gui_mch_init_has_finished = YES;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -162,12 +150,6 @@ gui_mch_exit(int rc)
|
||||
int
|
||||
gui_mch_open(void)
|
||||
{
|
||||
//NSLog(@"gui_mch_open()");
|
||||
|
||||
// This check is to avoid doing extra work when we're about to fork.
|
||||
if (!gui_mch_init_has_finished)
|
||||
return OK;
|
||||
|
||||
return [[MMBackend sharedInstance] openGUIWindow];
|
||||
}
|
||||
|
||||
@@ -234,13 +216,13 @@ gui_macvim_flush(void)
|
||||
if (delta > 1.0)
|
||||
delay = 1;
|
||||
|
||||
// We assume that each call corresponds roughly to one line out output.
|
||||
// We assume that each call corresponds roughly to one line of output.
|
||||
// When one page has scrolled by we increase the delay before the next
|
||||
// flush.
|
||||
if (++scrolls > gui.num_rows) {
|
||||
delay <<= 1;
|
||||
if (delay > 0x10000)
|
||||
delay = 0x10000;
|
||||
if (delay > 2048)
|
||||
delay = 2048;
|
||||
scrolls = 0;
|
||||
}
|
||||
|
||||
@@ -1283,8 +1265,10 @@ im_set_active(int active)
|
||||
// respectively.
|
||||
SInt32 systemScript = GetScriptManagerVariable(smSysScript);
|
||||
|
||||
if (!p_imdisable && smRoman != systemScript)
|
||||
KeyScript(active ? smKeySysScript : smKeyRoman);
|
||||
if (!p_imdisable && smRoman != systemScript) {
|
||||
int msgid = active ? ActivateKeyScriptID : DeactivateKeyScriptID;
|
||||
[[MMBackend sharedInstance] queueMessage:msgid properties:nil];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1718,6 +1702,9 @@ gui_mch_leave_fullscreen()
|
||||
void
|
||||
gui_mch_fuopt_update()
|
||||
{
|
||||
if (!gui.in_use)
|
||||
return;
|
||||
|
||||
guicolor_T fg, bg;
|
||||
if (fuoptions_flags & FUOPT_BGCOLOR_HLGROUP) {
|
||||
syn_id2colors(fuoptions_bgcolor, &fg, &bg);
|
||||
|
||||
+4
-1
@@ -1,7 +1,7 @@
|
||||
" System gvimrc file for MacVim
|
||||
"
|
||||
" Maintainer: Bjorn Winckler <bjorn.winckler@gmail.com>
|
||||
" Last Change: Sun Oct 04 2008
|
||||
" Last Change: Sun Mar 15 2009
|
||||
"
|
||||
" This is a work in progress. If you feel so inclined, please help me improve
|
||||
" this file.
|
||||
@@ -26,6 +26,9 @@ if !exists("colors_name")
|
||||
colorscheme macvim
|
||||
endif
|
||||
|
||||
" To make tabs more readable, the label only contains the tail of the file
|
||||
" name and the buffer modified flag.
|
||||
set guitablabel=%M%t
|
||||
|
||||
|
||||
" Send print jobs to Preview.app. This does not delete the temporary ps file
|
||||
|
||||
@@ -2,10 +2,25 @@
|
||||
|
||||
OUTDIR ?= .
|
||||
|
||||
$(OUTDIR)/MacVim-generic.icns: make_icons.py vim-noshadow-512.png
|
||||
$(OUTDIR)/MacVim-generic.icns: make_icons.py vim-noshadow-512.png loadfont.so Envy\ Code\ R\ Bold.ttf
|
||||
$(MAKE) -C makeicns
|
||||
/usr/bin/python make_icons.py $(OUTDIR)
|
||||
|
||||
loadfont.so: loadfont.c
|
||||
/usr/bin/python setup.py install --install-lib .
|
||||
|
||||
Envy\ Code\ R\ Bold.ttf: EnvyCodeR.zip
|
||||
unzip -jo EnvyCodeR.zip
|
||||
# unzip uses the file date from the zip file. Change the file date to
|
||||
# "now", so that the zip is not unzipped in every `make` run.`
|
||||
touch Envy\ Code\ R\ Bold.ttf
|
||||
|
||||
ENVYCODE_URL=http://download.damieng.com/latest/EnvyCodeR
|
||||
EnvyCodeR.zip:
|
||||
curl ${ENVYCODE_URL} --location -o EnvyCodeR.zip
|
||||
|
||||
clean:
|
||||
$(MAKE) -C makeicns clean
|
||||
rm -f $(OUTDIR)/MacVim-*.icns
|
||||
rm -f $(OUTDIR)/MacVim-*.icns loadfont.so *.pyc \
|
||||
EnvyCodeR.zip *.ttf *.reg *.txt
|
||||
rm -rf *.egginfo build # Created by setup.py
|
||||
|
||||
@@ -0,0 +1,605 @@
|
||||
from Foundation import *
|
||||
from AppKit import *
|
||||
|
||||
import itertools
|
||||
import math
|
||||
import operator
|
||||
import os
|
||||
|
||||
from optparse import OptionParser
|
||||
|
||||
|
||||
# Resources
|
||||
DEFAULT_BACKGROUND = '/System/Library/CoreServices/CoreTypes.bundle/' + \
|
||||
'Contents/Resources/GenericDocumentIcon.icns' # might require leopard?
|
||||
|
||||
|
||||
# Cache both images and background renderers globally
|
||||
imageCache = {}
|
||||
bgCache = {}
|
||||
|
||||
|
||||
# Make us not crash
|
||||
# http://www.cocoabuilder.com/archive/message/cocoa/2008/8/6/214964
|
||||
NSApplicationLoad()
|
||||
|
||||
|
||||
class Surface(object):
|
||||
"""Represents a simple bitmapped image."""
|
||||
|
||||
def __init__(self, *p, **kw):
|
||||
if not 'premultiplyAlpha' in kw:
|
||||
kw['premultiplyAlpha'] = True
|
||||
if len(p) == 1 and isinstance(p[0], NSBitmapImageRep):
|
||||
self.bitmapRep = p[0]
|
||||
elif len(p) == 2 and isinstance(p[0], int) and isinstance(p[1], int):
|
||||
format = NSAlphaFirstBitmapFormat
|
||||
if not kw['premultiplyAlpha']:
|
||||
format += NSAlphaNonpremultipliedBitmapFormat
|
||||
self.bitmapRep = NSBitmapImageRep.alloc().initWithBitmapDataPlanes_pixelsWide_pixelsHigh_bitsPerSample_samplesPerPixel_hasAlpha_isPlanar_colorSpaceName_bitmapFormat_bytesPerRow_bitsPerPixel_(
|
||||
None, p[0], p[1], 8, 4, True, False, NSDeviceRGBColorSpace,
|
||||
format, 0, 0)
|
||||
|
||||
if not hasattr(self, 'bitmapRep') or not self.bitmapRep:
|
||||
raise Exception('Failed to create surface: ' + str(p))
|
||||
|
||||
def size(self):
|
||||
return map(int, self.bitmapRep.size()) # cocoa returns floats. cocoa ftw
|
||||
|
||||
def data(self):
|
||||
"""Returns data in ARGB order (on intel, at least)."""
|
||||
r = self.bitmapRep
|
||||
if r.bitmapFormat() != (NSAlphaNonpremultipliedBitmapFormat |
|
||||
NSAlphaFirstBitmapFormat) or \
|
||||
r.bitsPerPixel() != 32 or \
|
||||
r.isPlanar() or \
|
||||
r.samplesPerPixel() != 4:
|
||||
raise Exception("Unsupported image format")
|
||||
return self.bitmapRep.bitmapData()
|
||||
|
||||
def save(self, filename):
|
||||
"""Saves image as png file."""
|
||||
self.bitmapRep.representationUsingType_properties_(NSPNGFileType, None) \
|
||||
.writeToFile_atomically_(filename, True)
|
||||
|
||||
def draw(self):
|
||||
self.bitmapRep.draw()
|
||||
|
||||
def context(self):
|
||||
# Note: Cocoa only supports contexts with premultiplied alpha
|
||||
return NSGraphicsContext.graphicsContextWithBitmapImageRep_(self.bitmapRep)
|
||||
|
||||
def copy(self):
|
||||
return Surface(self.bitmapRep.copy())
|
||||
|
||||
|
||||
class Image(object):
|
||||
"""Represents an image that can consist of several Surfaces."""
|
||||
|
||||
def __init__(self, param):
|
||||
if isinstance(param, str):
|
||||
self.image = NSImage.alloc().initWithContentsOfFile_(param)
|
||||
elif isinstance(param, Surface):
|
||||
self.image = NSImage.alloc().initWithSize_( param.size() )
|
||||
self.image.addRepresentation_(param.bitmapRep)
|
||||
|
||||
if not self.image:
|
||||
raise Exception('Failed to load image: ' + str(param))
|
||||
|
||||
def surfaceOfSize(self, w, h):
|
||||
"""Returns an ARGB, non-premultiplied surface of size w*h or throws."""
|
||||
r = None
|
||||
for rep in self.image.representations():
|
||||
# Cocoa reports fraction widths for pngs (wtf?!), so use round()
|
||||
if map(lambda x: int(round(x)), rep.size()) == [w, h]:
|
||||
r = rep
|
||||
break
|
||||
|
||||
# XXX: Resample in this case? That'd make the program easier to use, but
|
||||
# can silently create blurry backgrounds. Since this happens with
|
||||
# the app icon anyways, this might not be a huge deal?
|
||||
if not r:
|
||||
raise Exception('Unsupported size %dx%d', w, h)
|
||||
return Surface(r)
|
||||
|
||||
def blend(self):
|
||||
self.compositeInRect( ((0, 0), self.image.size()) )
|
||||
|
||||
def compositeInRect(self, r, mode=NSCompositeSourceOver):
|
||||
self.image.drawInRect_fromRect_operation_fraction_(r, NSZeroRect,
|
||||
mode, 1.0)
|
||||
|
||||
def sizes(self):
|
||||
s = set()
|
||||
for rep in self.image.representations():
|
||||
s.add(tuple(map(lambda x: int(round(x)), rep.size())))
|
||||
return s
|
||||
|
||||
|
||||
class Context(object):
|
||||
# Tiger has only Python2.3, so we can't use __enter__ / __exit__ for this :-(
|
||||
|
||||
def __init__(self, surface):
|
||||
NSGraphicsContext.saveGraphicsState()
|
||||
c = surface.context()
|
||||
c.setShouldAntialias_(True);
|
||||
c.setImageInterpolation_(NSImageInterpolationHigh);
|
||||
NSGraphicsContext.setCurrentContext_(c)
|
||||
|
||||
def done(self):
|
||||
NSGraphicsContext.restoreGraphicsState()
|
||||
|
||||
|
||||
class SplittableBackground(object):
|
||||
|
||||
def __init__(self, unsplitted, shouldSplit=True):
|
||||
self.unsplitted = unsplitted
|
||||
self.shouldSplit = shouldSplit
|
||||
self.ground = {}
|
||||
self.shadow = {}
|
||||
|
||||
def rawGroundAtSize(self, s):
|
||||
return self.unsplitted.surfaceOfSize(s, s)
|
||||
|
||||
def groundAtSize(self, s):
|
||||
if not self.shouldSplit:
|
||||
return self.rawGroundAtSize(s)
|
||||
self._performSplit(s)
|
||||
return self.ground[s]
|
||||
|
||||
def shadowAtSize(self, s):
|
||||
if not self.shouldSplit:
|
||||
return None
|
||||
self._performSplit(s)
|
||||
return self.shadow[s]
|
||||
|
||||
def _performSplit(self, s):
|
||||
if s in self.ground:
|
||||
assert s in self.shadow
|
||||
return
|
||||
assert s not in self.shadow
|
||||
ground, shadow = splitGenericDocumentIcon(self.unsplitted, s)
|
||||
self.ground[s] = ground
|
||||
self.shadow[s] = shadow
|
||||
|
||||
|
||||
class BackgroundRenderer(object):
|
||||
|
||||
def __init__(self, bg, icon=None, r={}):
|
||||
self.bgRenderer = bg
|
||||
self.icon = icon
|
||||
self.cache = {}
|
||||
self.rect = r
|
||||
|
||||
def drawIcon(self, s):
|
||||
if not self.icon:
|
||||
return
|
||||
|
||||
assert s in [16, 32, 128, 256, 512]
|
||||
a = list(self.rect[s])
|
||||
|
||||
# convert from `flow` coords to cocoa
|
||||
a[2] = -a[2] # mirror y
|
||||
|
||||
w, h = s*a[1], s*a[3]
|
||||
self.icon.compositeInRect( (((s-w)/2 + a[0], (s-h)/2 + a[2]), (w, h)) )
|
||||
|
||||
def drawAtSize(self, s):
|
||||
if not self.icon:
|
||||
# No need to split the background if no icons is interleaved -- take
|
||||
# the faster code path in that case.
|
||||
self.bgRenderer.rawGroundAtSize(s).draw()
|
||||
return
|
||||
|
||||
self.bgRenderer.groundAtSize(s).draw()
|
||||
self.drawIcon(s)
|
||||
if self.bgRenderer.shouldSplit:
|
||||
# shadow needs to be composited, so it needs to be in an image
|
||||
Image(self.bgRenderer.shadowAtSize(s)).blend()
|
||||
|
||||
def backgroundAtSize(self, s):
|
||||
if not s in self.cache:
|
||||
result = Surface(s, s)
|
||||
context = Context(result)
|
||||
self.drawAtSize(s)
|
||||
context.done()
|
||||
self.cache[s] = result
|
||||
return self.cache[s]
|
||||
|
||||
|
||||
def splitGenericDocumentIcon(img, s):
|
||||
"""Takes the generic document icon and splits it into a background and a
|
||||
shadow layer. For the 32x32 and 16x16 variants, the white pixels of the page
|
||||
curl are hardcoded into the otherwise transparent shadow layer."""
|
||||
|
||||
w, h = s, s
|
||||
r = img.surfaceOfSize(w, h)
|
||||
bps = 4*w
|
||||
data = r.data()
|
||||
|
||||
ground = Surface(w, h, premultiplyAlpha=False)
|
||||
shadow = Surface(w, h, premultiplyAlpha=False)
|
||||
|
||||
grounddata = ground.data()
|
||||
shadowdata = shadow.data()
|
||||
|
||||
for y in xrange(h):
|
||||
for x in xrange(w):
|
||||
idx = y*bps + 4*x
|
||||
ia, ir, ig, ib = data[idx:idx + 4]
|
||||
if ia != chr(255):
|
||||
# buffer objects don't support slice assignment :-(
|
||||
grounddata[idx] = ia
|
||||
grounddata[idx + 1] = ir
|
||||
grounddata[idx + 2] = ig
|
||||
grounddata[idx + 3] = ib
|
||||
shadowdata[idx] = chr(0)
|
||||
shadowdata[idx + 1] = chr(0)
|
||||
shadowdata[idx + 2] = chr(0)
|
||||
shadowdata[idx + 3] = chr(0)
|
||||
continue
|
||||
|
||||
assert ir == ig == ib
|
||||
grounddata[idx] = chr(255)
|
||||
grounddata[idx + 1] = chr(255)
|
||||
grounddata[idx + 2] = chr(255)
|
||||
grounddata[idx + 3] = chr(255)
|
||||
shadowdata[idx] = chr(255 - ord(ir))
|
||||
shadowdata[idx + 1] = chr(0)
|
||||
shadowdata[idx + 2] = chr(0)
|
||||
shadowdata[idx + 3] = chr(0)
|
||||
|
||||
# Special-case 16x16 and 32x32 cases: Make some pixels on the fold white.
|
||||
# Ideally, I could make the fold whiteish in all variants, but I can't.
|
||||
whitePix = { 16: [(10, 2), (10, 3), (11, 3), (10, 4), (11, 4), (12, 4)],
|
||||
32: [(21, 4), (21, 5), (22, 5), (21, 6), (22, 6), (23, 6)]}
|
||||
if (w, h) in [(16, 16), (32, 32)]:
|
||||
for x, y in whitePix[w]:
|
||||
idx = y*bps + 4*x
|
||||
shadowdata[idx] = chr(255)
|
||||
shadowdata[idx + 1] = chr(255)
|
||||
shadowdata[idx + 2] = chr(255)
|
||||
shadowdata[idx + 3] = chr(255)
|
||||
|
||||
return ground, shadow
|
||||
|
||||
|
||||
class TextRenderer(object):
|
||||
|
||||
def __init__(self):
|
||||
self.cache = {}
|
||||
|
||||
def attribsAtSize(self, s):
|
||||
if s not in self.cache:
|
||||
self.cache[s] = self._attribsAtSize(s)
|
||||
return self.cache[s]
|
||||
|
||||
def centeredStyle(self):
|
||||
style = NSMutableParagraphStyle.new()
|
||||
style.setParagraphStyle_(NSParagraphStyle.defaultParagraphStyle())
|
||||
style.setAlignment_(NSCenterTextAlignment)
|
||||
return style
|
||||
|
||||
def _attribsAtSize(self, s):
|
||||
# This looks not exactly like the font on Preview.app's document icons,
|
||||
# but I believe that's because Preview's icons are drawn by Photoshop,
|
||||
# and Adobe's font rendering is different from Apple's.
|
||||
fontname = 'LucidaGrande-Bold'
|
||||
|
||||
# Prepare text format
|
||||
fontsizes = { 512: 72.0, 256: 36.0, 128: 18.0, 32: 7.0, 16: 3.0 }
|
||||
# http://developer.apple.com/documentation/Cocoa/Conceptual/AttributedStrings/Articles/standardAttributes.html#//apple_ref/doc/uid/TP40004903
|
||||
attribs = {
|
||||
NSParagraphStyleAttributeName: self.centeredStyle(),
|
||||
NSForegroundColorAttributeName: NSColor.colorWithDeviceWhite_alpha_(
|
||||
0.34, 1),
|
||||
NSFontAttributeName: NSFont.fontWithName_size_(fontname, fontsizes[s])
|
||||
}
|
||||
|
||||
# tighten font a bit for some sizes
|
||||
if s in [256, 512]:
|
||||
attribs[NSKernAttributeName] = -1.0
|
||||
elif s == 32:
|
||||
attribs[NSKernAttributeName] = -0.25
|
||||
|
||||
if not attribs[NSFontAttributeName]:
|
||||
raise Exception('Failed to load font %s' % fontname)
|
||||
return attribs
|
||||
|
||||
def drawTextAtSize(self, text, s):
|
||||
"""Draws text `s` into the current context of size `s`."""
|
||||
|
||||
textRects = {
|
||||
512: ((0, 7), (512, 119)),
|
||||
128: ((0, 6), (128, 26.5)),
|
||||
256: ((0, 7), (256, 57)),
|
||||
16: ((1, 1), (15, 5)),
|
||||
#32: ((1, 1), (31, 9))
|
||||
}
|
||||
|
||||
attribs = self.attribsAtSize(s)
|
||||
text = NSString.stringWithString_(text)
|
||||
if s in [16, 128, 256, 512]:
|
||||
text.drawInRect_withAttributes_(textRects[s], attribs)
|
||||
elif s == 32:
|
||||
# Try to align text on pixel boundary:
|
||||
attribs = attribs.copy()
|
||||
attribs[NSParagraphStyleAttributeName] = \
|
||||
NSParagraphStyle.defaultParagraphStyle()
|
||||
ts = text.sizeWithAttributes_(attribs)
|
||||
text.drawAtPoint_withAttributes_( (math.floor((32.0-ts[0])/2) + 0.5, 1.5),
|
||||
attribs)
|
||||
|
||||
|
||||
class OfficeTextRenderer(TextRenderer):
|
||||
"""Uses Office's LucidaSans font for 32x32.
|
||||
|
||||
This font looks much better for certain strings (e.g. "PDF") but much worse
|
||||
for most others (e.g. "VIM", "JAVA") -- and office fonts are usually not
|
||||
installed. Hence, this class is better not used.
|
||||
"""
|
||||
|
||||
def _attribsAtSize(self, s):
|
||||
self.useOfficeFont = False
|
||||
attribs = TextRenderer._attribsAtSize(self, s)
|
||||
if s == 32:
|
||||
font = NSFont.fontWithName_size_('LucidaSans-Demi', 7.0)
|
||||
if font:
|
||||
attribs[NSFontAttributeName] = font
|
||||
attribs[NSKernAttributeName] = 0
|
||||
self.useOfficeFont = True
|
||||
return attribs
|
||||
|
||||
def drawTextAtSize(self, text, s):
|
||||
attribs = self.attribsAtSize(s)
|
||||
if not self.useOfficeFont or s != 32:
|
||||
TextRenderer.drawTextAtSize(self, text, s)
|
||||
return
|
||||
text = NSString.stringWithString_(text)
|
||||
text.drawInRect_withAttributes_( ((0, 1), (31, 11)), attribs)
|
||||
|
||||
|
||||
def createIcon(s, bg, textRenderer, text):
|
||||
|
||||
# Fill in background
|
||||
output = bg.backgroundAtSize(s).copy()
|
||||
|
||||
# Draw text on top of shadow
|
||||
context = Context(output)
|
||||
if s in text and text[s]:
|
||||
textRenderer.drawTextAtSize(text[s], s)
|
||||
context.done()
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def textDictFromTextList(l):
|
||||
assert 1 <= len(l) <= 3
|
||||
if len(l) == 1:
|
||||
return dict.fromkeys([16, 32, 128, 256, 512], l[0])
|
||||
elif len(l) == 2:
|
||||
return dict(zip([16, 32], 2*[l[1]]) + zip((128, 256, 512), 3*[l[0]]))
|
||||
elif len(l) == 3:
|
||||
return dict([(16, l[2]), (32, l[1])] + zip((128, 256, 512), 3*[l[0]]))
|
||||
|
||||
|
||||
def saveIcns(icons, icnsName, makeIcns='./makeicns'):
|
||||
"""Creates an icns file with several variants.
|
||||
|
||||
Params:
|
||||
icons: A dict that contains icon size as key and Surface as value.
|
||||
Valid keys are 512, 256, 128, 32, 16
|
||||
icnsname: Name of the output file
|
||||
"""
|
||||
# If IconFamily was less buggy, we could wrap it into a python module and
|
||||
# call it directly, which is about a lot faster. However, IconFamily does not
|
||||
# work with NSAlphaNonpremultipliedBitmapFormat correctly, so this has to
|
||||
# wait.
|
||||
#import IconFamily
|
||||
#typeDict = {
|
||||
#16: IconFamily.kSmall32BitData,
|
||||
#32: IconFamily.kLarge32BitData,
|
||||
#128: IconFamily.kThumbnail32BitData,
|
||||
#256: IconFamily.kIconServices256PixelDataARGB,
|
||||
#512: IconFamily.IconServices512PixelDataARGB,
|
||||
#}
|
||||
#maskDict = {
|
||||
#16: IconFamily.kSmall8BitMask,
|
||||
#32: IconFamily.kLarge8BitMask,
|
||||
#128: IconFamily.kThumbnail8BitMask,
|
||||
#}
|
||||
#output = IconFamily.IconFamily.iconFamily()
|
||||
#for s, icon in icons.items():
|
||||
#output.setIconFamilyElement_fromBitmapImageRep_(typeDict[s], icon.bitmapRep)
|
||||
#if s in maskDict:
|
||||
#output.setIconFamilyElement_fromBitmapImageRep_(
|
||||
#maskDict[s], icon.bitmapRep)
|
||||
#output.writeToFile_(icnsName)
|
||||
TMPFILE = 'docerator_tmp_%d.png'
|
||||
try:
|
||||
args = []
|
||||
for s, icon in icons.items():
|
||||
assert s in [512, 256, 128, 32, 16]
|
||||
assert icon.size() == [s, s]
|
||||
icon.save(TMPFILE % s)
|
||||
args.append('-%d %s' % (s, TMPFILE % s))
|
||||
return \
|
||||
os.system('%s %s -out %s' % (makeIcns, ' '.join(args), icnsName)) == 0
|
||||
finally:
|
||||
for s in icons:
|
||||
if os.access(TMPFILE % s, os.F_OK):
|
||||
os.remove(TMPFILE % s)
|
||||
|
||||
|
||||
def getOutname(options):
|
||||
def saneBasename(p):
|
||||
""" '/my/path/to/file.txt' -> 'file' """
|
||||
return os.path.splitext(os.path.basename(p))[0]
|
||||
textPart = 'Generic'
|
||||
if options.text:
|
||||
textPart = options.text.split(',')[0]
|
||||
if options.appicon:
|
||||
base = saneBasename(options.appicon)
|
||||
else:
|
||||
base = saneBasename(getBgName(options))
|
||||
return '%s-%s.icns' % (base, textPart)
|
||||
|
||||
|
||||
def cachedImage(filename):
|
||||
absPath = os.path.abspath(filename)
|
||||
if not absPath in imageCache:
|
||||
imageCache[absPath] = Image(absPath)
|
||||
return imageCache[absPath]
|
||||
|
||||
|
||||
def cachedBackground(img, split):
|
||||
key = (img, split)
|
||||
if not key in bgCache:
|
||||
bgCache[key] = SplittableBackground(img, shouldSplit=split)
|
||||
return bgCache[key]
|
||||
|
||||
|
||||
# taken from running flow on preview
|
||||
defaultRects = {
|
||||
16: (-0.30890000000000001, 0.4919, -1.2968, 0.4743),
|
||||
32: (-0.27810000000000001,
|
||||
0.58930000000000005,
|
||||
-2.2292999999999998,
|
||||
0.57140000000000002),
|
||||
128: (1.1774, 0.56820000000000004, -0.8246, 0.56799999999999995),
|
||||
256: (0.5917, 0.56489999999999996, -1.8994, 0.56499999999999995),
|
||||
512: (0.68700000000000006,
|
||||
0.56530000000000002,
|
||||
-4.2813999999999997,
|
||||
0.56540000000000001)
|
||||
}
|
||||
|
||||
|
||||
def getBgName(options):
|
||||
if not hasattr(options, 'background') \
|
||||
or options.background in ['default-split', 'default-unsplit']:
|
||||
return DEFAULT_BACKGROUND
|
||||
else:
|
||||
return options.background
|
||||
|
||||
|
||||
class IconGenerator(object):
|
||||
def __init__(self, options):
|
||||
if hasattr(options, 'textrenderer') and options.textrenderer:
|
||||
self.textRenderer = options.textrenderer()
|
||||
else:
|
||||
self.textRenderer = TextRenderer()
|
||||
|
||||
# Prepare input images
|
||||
splitBackground = options.background == 'default-split'
|
||||
self.bgIcon = cachedImage(getBgName(options))
|
||||
|
||||
self.testIcon = None
|
||||
if options.appicon:
|
||||
self.testIcon = cachedImage(options.appicon)
|
||||
|
||||
rects = defaultRects.copy()
|
||||
rects[16] = [ 0.0000, 0.5000, -1.0000, 0.5000] # manually, better
|
||||
if hasattr(options, 'rects'):
|
||||
rects.update(options.rects)
|
||||
|
||||
bg = cachedBackground(self.bgIcon, splitBackground)
|
||||
|
||||
if hasattr(options, 'backgroundrenderer') and options.backgroundrenderer:
|
||||
self.bgRenderer = options.backgroundrenderer(bg, self.testIcon, rects)
|
||||
else:
|
||||
self.bgRenderer = BackgroundRenderer(bg, self.testIcon, rects)
|
||||
|
||||
self.testtext = textDictFromTextList(options.text.split(','))
|
||||
|
||||
def createIconAtSize(self, s):
|
||||
return createIcon(s, self.bgRenderer, self.textRenderer, self.testtext)
|
||||
|
||||
|
||||
def iconGenerator(**kwargs):
|
||||
return IconGenerator(optsFromDict(**kwargs))
|
||||
|
||||
|
||||
def makedocicon_opts(options):
|
||||
renderer = IconGenerator(options)
|
||||
|
||||
if hasattr(options, 'sizes') and options.sizes:
|
||||
if isinstance(options.sizes, list):
|
||||
sizes = options.sizes
|
||||
else:
|
||||
sizes = map(int, options.sizes.split(','))
|
||||
else:
|
||||
sizes = renderer.bgIcon.sizes()
|
||||
if renderer.testIcon:
|
||||
sizes = sizes.intersection(renderer.testIcon.sizes())
|
||||
sizes = sorted(map(operator.itemgetter(0), sizes))
|
||||
|
||||
icons = dict([(s, renderer.createIconAtSize(s)) for s in sizes])
|
||||
|
||||
if options.debug:
|
||||
for s, icon in icons.iteritems():
|
||||
icon.save(options.debug % s)
|
||||
|
||||
if hasattr(options, 'outname') and options.outname:
|
||||
outname = options.outname
|
||||
else:
|
||||
outname = getOutname(options)
|
||||
if saveIcns(icons, outname, options.makeicns):
|
||||
print 'Wrote', outname
|
||||
else:
|
||||
print 'Failed to write %s. Make sure makeicns is in your path.' % outname
|
||||
|
||||
|
||||
def optsFromDict(**kwargs):
|
||||
options, _ = getopts().parse_args([]) # get default options
|
||||
for k in kwargs:
|
||||
setattr(options, k, kwargs[k])
|
||||
return options
|
||||
|
||||
|
||||
def makedocicon(**kwargs):
|
||||
makedocicon_opts(optsFromDict(**kwargs))
|
||||
|
||||
|
||||
def makedocicons_opts(options):
|
||||
if not hasattr(options, 'text') or not options.text:
|
||||
options.text = ['']
|
||||
texts = options.text
|
||||
for text in texts:
|
||||
options.text = text
|
||||
makedocicon_opts(options)
|
||||
|
||||
|
||||
def makedocicons(**kwargs):
|
||||
makedocicons_opts(optsFromDict(**kwargs))
|
||||
|
||||
|
||||
def getopts():
|
||||
parser = OptionParser(usage='%prog [options]', version='%prog 1.01')
|
||||
parser.add_option('--background', '--bg', default='default-split',
|
||||
help='Used as background (special values: "default-split" (default), ' \
|
||||
'"default-unsplit").')
|
||||
parser.add_option('--appicon', help='App icon, defaults to no icon.')
|
||||
|
||||
parser.add_option('--text', help='Text on icon. Defaults to empty. '
|
||||
'More than one text is supported, multiple docicons are generated in '
|
||||
'that case.', action='append')
|
||||
parser.add_option('--sizes', help='Sizes of icons. ' \
|
||||
'Defaults to all sizes available in input appicon. Example: "512,128,16"')
|
||||
# XXX(Nico): This has to go
|
||||
parser.add_option('--debug', help='If set, write out pngs for all variants.' \
|
||||
' This needs to look like "debug%d.png".')
|
||||
# XXX(Nico): This has to go once IconFamily is less buggy and can be used
|
||||
# directly
|
||||
parser.add_option('--makeicns', help='Path to makeicns binary',
|
||||
default='./makeicns')
|
||||
return parser
|
||||
|
||||
|
||||
def main():
|
||||
options, args = getopts().parse_args()
|
||||
makedocicons_opts(options)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,65 @@
|
||||
import docerator
|
||||
import unittest
|
||||
|
||||
|
||||
class TextDictFromTextListTest(unittest.TestCase):
|
||||
|
||||
def testBasic(self):
|
||||
|
||||
self.assertEquals({16: 'a', 32: 'a', 128: 'a', 256: 'a', 512: 'a'},
|
||||
docerator.textDictFromTextList(['a']))
|
||||
self.assertEquals({16: 'b', 32: 'b', 128: 'a', 256: 'a', 512: 'a'},
|
||||
docerator.textDictFromTextList(['a', 'b']))
|
||||
self.assertEquals({16: 'c', 32: 'b', 128: 'a', 256: 'a', 512: 'a'},
|
||||
docerator.textDictFromTextList(['a', 'b', 'c']))
|
||||
|
||||
|
||||
class OutnameTest(unittest.TestCase):
|
||||
|
||||
class FakeOptions(object):
|
||||
def __init__(self, **kwargs):
|
||||
for k in kwargs:
|
||||
self.__setattr__(k, kwargs[k])
|
||||
|
||||
def testBasic(self):
|
||||
options = OutnameTest.FakeOptions(
|
||||
appicon = '/Applications/iTunes.app/Contents/Resources/iTunes.icns',
|
||||
text='MP3')
|
||||
self.assertEquals('iTunes-MP3.icns', docerator.getOutname(options))
|
||||
|
||||
def testTextList(self):
|
||||
options = OutnameTest.FakeOptions(
|
||||
appicon = '/Applications/iTunes.app/Contents/Resources/iTunes.icns',
|
||||
text='PYTHON,PY')
|
||||
self.assertEquals('iTunes-PYTHON.icns',
|
||||
docerator.getOutname(options))
|
||||
|
||||
def testEmptyText(self):
|
||||
options = OutnameTest.FakeOptions(
|
||||
appicon = '/Applications/iTunes.app/Contents/Resources/iTunes.icns',
|
||||
text='')
|
||||
self.assertEquals('iTunes-Generic.icns', docerator.getOutname(options))
|
||||
options = OutnameTest.FakeOptions(
|
||||
appicon = '/Applications/iTunes.app/Contents/Resources/iTunes.icns',
|
||||
text=None)
|
||||
self.assertEquals('iTunes-Generic.icns',
|
||||
docerator.getOutname(options))
|
||||
|
||||
def testEmptyIcon(self):
|
||||
options = OutnameTest.FakeOptions(appicon=None, text='MP3')
|
||||
self.assertEquals('GenericDocumentIcon-MP3.icns',
|
||||
docerator.getOutname(options))
|
||||
options = OutnameTest.FakeOptions(appicon=None, text='')
|
||||
self.assertEquals('GenericDocumentIcon-Generic.icns',
|
||||
docerator.getOutname(options))
|
||||
options = OutnameTest.FakeOptions(appicon=None, text='',
|
||||
background='/Applications/Bla/bgicon.icns')
|
||||
self.assertEquals('bgicon-Generic.icns',
|
||||
docerator.getOutname(options))
|
||||
|
||||
|
||||
# XXX(Nico): Look at the doctest module.
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,56 @@
|
||||
// A small python module that registers a font with ATS, given the name of
|
||||
// the font.
|
||||
|
||||
#include <Python/Python.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
static PyObject* loadfont(PyObject* self, PyObject* args) {
|
||||
PyObject* result = Py_False;
|
||||
const char* path = NULL;
|
||||
int ok = PyArg_ParseTuple(args, "s", &path);
|
||||
|
||||
if (ok) {
|
||||
CFStringRef componentPath = CFStringCreateWithCString(kCFAllocatorDefault,
|
||||
path, kCFStringEncodingUTF8);
|
||||
CFURLRef componentURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
|
||||
componentPath, kCFURLPOSIXPathStyle, false);
|
||||
FSRef fsref;
|
||||
|
||||
if (CFURLGetFSRef(componentURL, &fsref)) {
|
||||
OSStatus err = noErr;
|
||||
ATSFontContainerRef fontContainerRef; // we don't deactivate the font
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4)
|
||||
err = ATSFontActivateFromFileReference(&fsref,
|
||||
kATSFontContextLocal, kATSFontFormatUnspecified, NULL,
|
||||
kATSOptionFlagsDefault, &fontContainerRef);
|
||||
#else
|
||||
FSSpec fsSpec;
|
||||
FSRef fsRef;
|
||||
if ((err = FSGetCatalogInfo(
|
||||
&fsRef, kFSCatInfoNone, NULL, NULL, &fsSpec, NULL)) == noErr) {
|
||||
err = ATSFontActivateFromFileSpecification(&fsSpec,
|
||||
kATSFontContextLocal, kATSFontFormatUnspecified, NULL,
|
||||
kATSOptionFlagsDefault, &fontContainerRef);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (err == noErr) {
|
||||
result = Py_True;
|
||||
}
|
||||
}
|
||||
CFRelease(componentURL);
|
||||
CFRelease(componentPath);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyMethodDef LoadfontMethods[] = {
|
||||
{ "loadfont", loadfont, METH_VARARGS, "Locally activates font from file." },
|
||||
{ NULL, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC initloadfont(void) {
|
||||
Py_InitModule("loadfont", LoadfontMethods);
|
||||
}
|
||||
+95
-449
@@ -1,31 +1,51 @@
|
||||
# Creates a document icon from an app icon and an optional text.
|
||||
|
||||
# The font is not quite right, use this script to create a document icon
|
||||
# for 'PDF' and compare the D with the D in Preview's pdf.icns
|
||||
# Creates all of MacVim document icons.
|
||||
|
||||
# http://www.macresearch.org/cocoa-scientists-part-xx-python-scriptersmeet-cocoa
|
||||
try:
|
||||
from Foundation import *
|
||||
# Make us independent of sysprefs->appearance->antialias fonts smaller than...
|
||||
# Needs to happen before docerator is imported.
|
||||
from AppKit import NSUserDefaults
|
||||
prefs = NSUserDefaults.standardUserDefaults()
|
||||
prefs.setInteger_forKey_(4, 'AppleAntiAliasingThreshold')
|
||||
|
||||
import docerator
|
||||
|
||||
# Load Envy Code R from a file and register it under its postscript name
|
||||
# Thanks to DamienG for this font (redistributed with permission):
|
||||
# http://damieng.com/blog/2008/05/26/envy-code-r-preview-7-coding-font-released
|
||||
import loadfont
|
||||
loadfont.loadfont('Envy Code R Bold.ttf')
|
||||
|
||||
from Foundation import NSString
|
||||
from AppKit import *
|
||||
|
||||
dont_create = False
|
||||
except:
|
||||
dont_create = True # most likely because we're on tiger
|
||||
NSCompositeSourceOver = 2
|
||||
|
||||
import math
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
# icon types
|
||||
LARGE = 0 # 512, 128, 32, 16; about 96kB
|
||||
SMALL = 1 # 128, 32, 16; about 36kB
|
||||
LINK = 2 # Create link to generic icon; 4kB (== smallest block size on HFS+)
|
||||
|
||||
# path to makeicns binary
|
||||
iconsizes = {
|
||||
SMALL: [128, 32, 16],
|
||||
LARGE: [512, 128, 32, 16],
|
||||
}
|
||||
|
||||
|
||||
# Resources
|
||||
MAKEICNS = 'makeicns/makeicns'
|
||||
APPICON = 'vim-noshadow-512.png'
|
||||
DEFAULT_BACKGROUND = '/System/Library/CoreServices/CoreTypes.bundle/' + \
|
||||
'Contents/Resources/GenericDocumentIcon.icns'
|
||||
|
||||
|
||||
# List of icons to create
|
||||
# XXX: 32x32 variants only support 3-4 letters of text
|
||||
GENERIC_ICON_NAME = 'MacVim-generic'
|
||||
vimIcons = {
|
||||
GENERIC_ICON_NAME: [u'', LARGE],
|
||||
@@ -36,19 +56,19 @@ vimIcons = {
|
||||
'MacVim-c': [u'C', SMALL],
|
||||
'MacVim-m': [u'M', SMALL],
|
||||
'MacVim-mm': [u'MM', SMALL],
|
||||
'MacVim-cpp': [u'C\uff0b\uff0b', SMALL], # fullwidth plusses
|
||||
'MacVim-cpp': [u'C\uff0b\uff0b,C++,C++', SMALL], # fullwidth plusses
|
||||
'MacVim-java': [u'JAVA', SMALL],
|
||||
'MacVim-f': [u'FTRAN', SMALL],
|
||||
'MacVim-html': [u'HTML', SMALL],
|
||||
'MacVim-xml': [u'XML', SMALL],
|
||||
'MacVim-js': [u'JS', SMALL],
|
||||
'MacVim-perl': [u'PERL', SMALL],
|
||||
'MacVim-py': [u'PYTHON', SMALL],
|
||||
'MacVim-perl': [u'PERL,PL', SMALL],
|
||||
'MacVim-py': [u'PYTHON,PY', SMALL],
|
||||
'MacVim-php': [u'PHP', SMALL],
|
||||
'MacVim-rb': [u'RUBY', SMALL],
|
||||
'MacVim-rb': [u'RUBY,RB', SMALL],
|
||||
'MacVim-bash': [u'SH', SMALL],
|
||||
'MacVim-patch': [u'DIFF', SMALL],
|
||||
'MacVim-applescript': [u'\uf8ffSCPT', SMALL], # apple sign
|
||||
'MacVim-applescript': [u'\uf8ffSCPT,\uf8ffS', SMALL], # apple sign
|
||||
'MacVim-as': [u'FLASH', LINK],
|
||||
'MacVim-asp': [u'ASP', LINK],
|
||||
'MacVim-bib': [u'BIB', LINK],
|
||||
@@ -61,8 +81,8 @@ vimIcons = {
|
||||
'MacVim-css': [u'CSS', SMALL],
|
||||
'MacVim-dtd': [u'DTD', LINK],
|
||||
'MacVim-dylan': [u'DYLAN', LINK],
|
||||
'MacVim-erl': [u'ERLANG', SMALL],
|
||||
'MacVim-fscript': [u'FSCPT', SMALL],
|
||||
'MacVim-erl': [u'ERLANG,ERL', SMALL],
|
||||
'MacVim-fscript': [u'FSCPT,FSCR,FS', SMALL],
|
||||
'MacVim-hs': [u'HS', SMALL],
|
||||
'MacVim-inc': [u'INC', LINK],
|
||||
'MacVim-ics': [u'ICS', SMALL],
|
||||
@@ -71,385 +91,21 @@ vimIcons = {
|
||||
'MacVim-bsh': [u'BSH', LINK],
|
||||
'MacVim-properties': [u'PROP', LINK],
|
||||
'MacVim-jsp': [u'JSP', SMALL],
|
||||
'MacVim-lisp': [u'LISP', SMALL],
|
||||
'MacVim-lisp': [u'LISP,LISP,LSP', SMALL],
|
||||
'MacVim-log': [u'LOG', SMALL],
|
||||
'MacVim-wiki': [u'WIKI', SMALL],
|
||||
'MacVim-ps': [u'PS', LINK],
|
||||
#'MacVim-plist': [u'PLIST', SMALL],
|
||||
'MacVim-sch': [u'SCHEME', SMALL],
|
||||
'MacVim-sch': [u'SCHEME,SCM', SMALL],
|
||||
'MacVim-sql': [u'SQL', SMALL],
|
||||
'MacVim-tcl': [u'TCL', SMALL],
|
||||
'MacVim-xsl': [u'XSL', LINK],
|
||||
'MacVim-vcf': [u'VCARD', SMALL],
|
||||
'MacVim-vb': [u'VBASIC', LINK],
|
||||
'MacVim-yaml': [u'YAML', SMALL],
|
||||
'MacVim-vcf': [u'VCARD,VCF', SMALL],
|
||||
'MacVim-vb': [u'VBASIC,VB', LINK],
|
||||
'MacVim-yaml': [u'YAML,YAML,YML', SMALL],
|
||||
'MacVim-gtd': [u'GTD', LINK],
|
||||
}
|
||||
|
||||
shorttext = {
|
||||
u'MacVim-py': u'PY',
|
||||
u'MacVim-rb': u'RB',
|
||||
u'MacVim-perl': u'PL',
|
||||
u'MacVim-applescript': u'\uf8ffS',
|
||||
u'MacVim-erl': u'ERL',
|
||||
u'MacVim-fscript': u'FSCR',
|
||||
u'MacVim-sch': u'SCM',
|
||||
u'MacVim-vcf': u'VCF',
|
||||
u'MacVim-vb': u'VB',
|
||||
}
|
||||
|
||||
|
||||
# Resources
|
||||
BACKGROUND = '/System/Library/CoreServices/CoreTypes.bundle/' + \
|
||||
'Contents/Resources/GenericDocumentIcon.icns' # might require leopard?
|
||||
APPICON = 'vim-noshadow-512.png'
|
||||
#APPICON = 'vim-noshadow-no-v-512.png'
|
||||
|
||||
class Surface(object):
|
||||
"""Represents a simple bitmapped image."""
|
||||
|
||||
def __init__(self, *p, **kw):
|
||||
if not 'premultiplyAlpha' in kw:
|
||||
kw['premultiplyAlpha'] = True
|
||||
if len(p) == 1 and isinstance(p[0], NSBitmapImageRep):
|
||||
self.bitmapRep = p[0]
|
||||
elif len(p) == 2 and isinstance(p[0], int) and isinstance(p[1], int):
|
||||
format = NSAlphaFirstBitmapFormat
|
||||
if not kw['premultiplyAlpha']:
|
||||
format += NSAlphaNonpremultipliedBitmapFormat
|
||||
self.bitmapRep = NSBitmapImageRep.alloc().initWithBitmapDataPlanes_pixelsWide_pixelsHigh_bitsPerSample_samplesPerPixel_hasAlpha_isPlanar_colorSpaceName_bitmapFormat_bytesPerRow_bitsPerPixel_(
|
||||
None, p[0], p[1], 8, 4, True, False, NSDeviceRGBColorSpace,
|
||||
format, 0, 0)
|
||||
|
||||
if not hasattr(self, 'bitmapRep') or not self.bitmapRep:
|
||||
raise Exception('Failed to create surface: ' + str(p))
|
||||
|
||||
def size(self):
|
||||
return map(int, self.bitmapRep.size()) # cocoa returns floats. cocoa ftw
|
||||
|
||||
def data(self):
|
||||
"""Returns data in ARGB order (on intel, at least)."""
|
||||
r = self.bitmapRep
|
||||
if r.bitmapFormat() != (NSAlphaNonpremultipliedBitmapFormat |
|
||||
NSAlphaFirstBitmapFormat) or \
|
||||
r.bitsPerPixel() != 32 or \
|
||||
r.isPlanar() or \
|
||||
r.samplesPerPixel() != 4:
|
||||
raise Exception("Unsupported image format")
|
||||
return self.bitmapRep.bitmapData()
|
||||
|
||||
def save(self, filename):
|
||||
"""Saves image as png file."""
|
||||
self.bitmapRep.representationUsingType_properties_(NSPNGFileType, None) \
|
||||
.writeToFile_atomically_(filename, True)
|
||||
|
||||
def draw(self):
|
||||
self.bitmapRep.draw()
|
||||
|
||||
def context(self):
|
||||
# Note: Cocoa only supports contexts with premultiplied alpha
|
||||
return NSGraphicsContext.graphicsContextWithBitmapImageRep_(self.bitmapRep)
|
||||
|
||||
def copy(self):
|
||||
return Surface(self.bitmapRep.copy())
|
||||
|
||||
|
||||
class Image(object):
|
||||
"""Represents an image that can consist of several Surfaces."""
|
||||
|
||||
def __init__(self, param):
|
||||
if isinstance(param, str):
|
||||
self.image = NSImage.alloc().initWithContentsOfFile_(param)
|
||||
elif isinstance(param, Surface):
|
||||
self.image = NSImage.alloc().initWithSize_( param.size() )
|
||||
self.image.addRepresentation_(param.bitmapRep)
|
||||
|
||||
if not self.image:
|
||||
raise Exception('Failed to load image: ' + str(filename))
|
||||
|
||||
def surfaceOfSize(self, w, h):
|
||||
"""Returns an ARGB, non-premultiplied surface of size w*h or throws."""
|
||||
r = None
|
||||
for rep in self.image.representations():
|
||||
if map(int, rep.size()) == [w, h]:
|
||||
r = rep
|
||||
break
|
||||
if not r:
|
||||
raise Exception('Unsupported size %dx%d', w, h)
|
||||
return Surface(r)
|
||||
|
||||
def blend(self):
|
||||
self.compositeInRect( ((0, 0), self.image.size()) )
|
||||
|
||||
def compositeInRect(self, r, mode=NSCompositeSourceOver):
|
||||
self.image.drawInRect_fromRect_operation_fraction_(r, NSZeroRect,
|
||||
mode, 1.0)
|
||||
|
||||
|
||||
class Context(object):
|
||||
# Tiger has only Python2.3, so we can't use __enter__ / __exit__ for this :-(
|
||||
|
||||
def __init__(self, surface):
|
||||
NSGraphicsContext.saveGraphicsState()
|
||||
c = surface.context()
|
||||
c.setShouldAntialias_(True);
|
||||
c.setImageInterpolation_(NSImageInterpolationHigh);
|
||||
NSGraphicsContext.setCurrentContext_(c)
|
||||
|
||||
def done(self):
|
||||
NSGraphicsContext.restoreGraphicsState()
|
||||
|
||||
|
||||
class SplittableBackground(object):
|
||||
|
||||
def __init__(self, unsplitted, shouldSplit=True):
|
||||
self.unsplitted = unsplitted
|
||||
self.shouldSplit = shouldSplit
|
||||
self.ground = {}
|
||||
self.shadow = {}
|
||||
|
||||
def rawGroundAtSize(self, s):
|
||||
return self.unsplitted.surfaceOfSize(s, s)
|
||||
|
||||
def groundAtSize(self, s):
|
||||
if not self.shouldSplit:
|
||||
return self.rawGroundAtSize(s)
|
||||
self._performSplit(s)
|
||||
return self.ground[s]
|
||||
|
||||
def shadowAtSize(self, s):
|
||||
if not self.shouldSplit:
|
||||
return None
|
||||
self._performSplit(s)
|
||||
return self.shadow[s]
|
||||
|
||||
def _performSplit(self, s):
|
||||
if s in self.ground:
|
||||
assert s in self.shadow
|
||||
return
|
||||
assert s not in self.shadow
|
||||
ground, shadow = splitGenericDocumentIcon(self.unsplitted, s)
|
||||
self.ground[s] = ground
|
||||
self.shadow[s] = shadow
|
||||
|
||||
|
||||
class BackgroundRenderer(object):
|
||||
|
||||
def __init__(self, bg, icon=None):
|
||||
self.bgRenderer = bg
|
||||
self.icon = icon
|
||||
self.cache = {}
|
||||
|
||||
def drawIcon(self, s):
|
||||
if not self.icon:
|
||||
return
|
||||
# found by flow program, better than anything i came up with manually before
|
||||
# (except for the 16x16 variant :-( )
|
||||
transforms = {
|
||||
512: [ 0.7049, 0.5653, -4.2432, 0.5656],
|
||||
256: [ 0.5690, 0.5658, -1.9331, 0.5656],
|
||||
128: [ 1.1461, 0.5684, -0.8482, 0.5681],
|
||||
|
||||
32: [-0.2682, 0.5895, -2.2130, 0.5701], # intensity
|
||||
#32: [-0.2731, 0.5898, -2.2262, 0.5729], # rgb (no rmse difference)
|
||||
|
||||
#16: [-0.3033, 0.4909, -1.3235, 0.4790], # program, intensity
|
||||
#16: [-0.3087, 0.4920, -1.2990, 0.4750], # program, rgb mode
|
||||
16: [ 0.0000, 0.5000, -1.0000, 0.5000], # manually, better
|
||||
}
|
||||
|
||||
assert s in [16, 32, 128, 256, 512]
|
||||
a = transforms[s]
|
||||
|
||||
# convert from `flow` coords to cocoa
|
||||
a[2] = -a[2] # mirror y
|
||||
|
||||
w, h = s*a[1], s*a[3]
|
||||
self.icon.compositeInRect( (((s-w)/2 + a[0], (s-h)/2 + a[2]), (w, h)) )
|
||||
|
||||
def drawAtSize(self, s):
|
||||
self.bgRenderer.groundAtSize(s).draw()
|
||||
self.drawIcon(s)
|
||||
if self.bgRenderer.shouldSplit:
|
||||
# shadow needs to be composited, so it needs to be in an image
|
||||
Image(self.bgRenderer.shadowAtSize(s)).blend()
|
||||
|
||||
def backgroundAtSize(self, s):
|
||||
if not s in self.cache:
|
||||
result = Surface(s, s)
|
||||
context = Context(result)
|
||||
self.drawAtSize(s)
|
||||
context.done()
|
||||
self.cache[s] = result
|
||||
return self.cache[s]
|
||||
|
||||
|
||||
def splitGenericDocumentIcon(img, s):
|
||||
"""Takes the generic document icon and splits it into a background and a
|
||||
shadow layer. For the 32x32 and 16x16 variants, the white pixels of the page
|
||||
curl are hardcoded into the otherwise transparent shadow layer."""
|
||||
|
||||
w, h = s, s
|
||||
r = img.surfaceOfSize(w, h)
|
||||
bps = 4*w
|
||||
data = r.data()
|
||||
|
||||
ground = Surface(w, h, premultiplyAlpha=False)
|
||||
shadow = Surface(w, h, premultiplyAlpha=False)
|
||||
|
||||
grounddata = ground.data()
|
||||
shadowdata = shadow.data()
|
||||
|
||||
for y in xrange(h):
|
||||
for x in xrange(w):
|
||||
idx = y*bps + 4*x
|
||||
ia, ir, ig, ib = data[idx:idx + 4]
|
||||
if ia != chr(255):
|
||||
# buffer objects don't support slice assignment :-(
|
||||
grounddata[idx] = ia
|
||||
grounddata[idx + 1] = ir
|
||||
grounddata[idx + 2] = ig
|
||||
grounddata[idx + 3] = ib
|
||||
shadowdata[idx] = chr(0)
|
||||
shadowdata[idx + 1] = chr(0)
|
||||
shadowdata[idx + 2] = chr(0)
|
||||
shadowdata[idx + 3] = chr(0)
|
||||
continue
|
||||
|
||||
assert ir == ig == ib
|
||||
grounddata[idx] = chr(255)
|
||||
grounddata[idx + 1] = chr(255)
|
||||
grounddata[idx + 2] = chr(255)
|
||||
grounddata[idx + 3] = chr(255)
|
||||
shadowdata[idx] = chr(255 - ord(ir))
|
||||
shadowdata[idx + 1] = chr(0)
|
||||
shadowdata[idx + 2] = chr(0)
|
||||
shadowdata[idx + 3] = chr(0)
|
||||
|
||||
# Special-case 16x16 and 32x32 cases: Make some pixels on the fold white.
|
||||
# Ideally, I could make the fold whiteish in all variants, but I can't.
|
||||
whitePix = { 16: [(10, 2), (10, 3), (11, 3), (10, 4), (11, 4), (12, 4)],
|
||||
32: [(21, 4), (21, 5), (22, 5), (21, 6), (22, 6), (23, 6)]}
|
||||
if (w, h) in [(16, 16), (32, 32)]:
|
||||
for x, y in whitePix[w]:
|
||||
idx = y*bps + 4*x
|
||||
shadowdata[idx] = chr(255)
|
||||
shadowdata[idx + 1] = chr(255)
|
||||
shadowdata[idx + 2] = chr(255)
|
||||
shadowdata[idx + 3] = chr(255)
|
||||
|
||||
return ground, shadow
|
||||
|
||||
|
||||
class TextRenderer(object):
|
||||
|
||||
def __init__(self):
|
||||
self.cache = {}
|
||||
|
||||
def attribsAtSize(self, s):
|
||||
if s not in self.cache:
|
||||
self.cache[s] = self._attribsAtSize(s)
|
||||
return self.cache[s]
|
||||
|
||||
def centeredStyle(self):
|
||||
style = NSMutableParagraphStyle.new()
|
||||
style.setParagraphStyle_(NSParagraphStyle.defaultParagraphStyle())
|
||||
style.setAlignment_(NSCenterTextAlignment)
|
||||
return style
|
||||
|
||||
def _attribsAtSize(self, s):
|
||||
# This looks not exactly like the font on Preview.app's document icons,
|
||||
# but I believe that's because Preview's icons are drawn by Photoshop,
|
||||
# and Adobe's font rendering is different from Apple's.
|
||||
fontname = 'LucidaGrande-Bold'
|
||||
|
||||
# Prepare text format
|
||||
fontsizes = { 512: 72.0, 256: 36.0, 128: 18.0, 32: 7.0, 16: 3.0 }
|
||||
# http://developer.apple.com/documentation/Cocoa/Conceptual/AttributedStrings/Articles/standardAttributes.html#//apple_ref/doc/uid/TP40004903
|
||||
attribs = {
|
||||
NSParagraphStyleAttributeName: self.centeredStyle(),
|
||||
NSForegroundColorAttributeName: NSColor.colorWithDeviceWhite_alpha_(
|
||||
0.34, 1),
|
||||
NSFontAttributeName: NSFont.fontWithName_size_(fontname, fontsizes[s])
|
||||
}
|
||||
|
||||
# tighten font a bit for some sizes
|
||||
if s in [256, 512]:
|
||||
attribs[NSKernAttributeName] = -1.0
|
||||
elif s == 32:
|
||||
attribs[NSKernAttributeName] = -0.25
|
||||
|
||||
if not attribs[NSFontAttributeName]:
|
||||
raise Exception('Failed to load font %s' % fontname)
|
||||
return attribs
|
||||
|
||||
def drawTextAtSize(self, text, s):
|
||||
"""Draws text `s` into the current context of size `s`."""
|
||||
|
||||
textRects = {
|
||||
512: ((0, 7), (512, 119)),
|
||||
128: ((0, 6), (128, 26.5)),
|
||||
256: ((0, 7), (256, 57)),
|
||||
16: ((1, 1), (15, 5)),
|
||||
#32: ((1, 1), (31, 9))
|
||||
}
|
||||
|
||||
attribs = self.attribsAtSize(s)
|
||||
text = NSString.stringWithString_(text)
|
||||
if s in [16, 128, 256, 512]:
|
||||
text.drawInRect_withAttributes_(textRects[s], attribs)
|
||||
elif s == 32:
|
||||
# Try to align text on pixel boundary:
|
||||
attribs = attribs.copy()
|
||||
attribs[NSParagraphStyleAttributeName] = \
|
||||
NSParagraphStyle.defaultParagraphStyle()
|
||||
ts = text.sizeWithAttributes_(attribs)
|
||||
text.drawAtPoint_withAttributes_( (math.floor((32.0-ts[0])/2) + 0.5, 1.5),
|
||||
attribs)
|
||||
|
||||
|
||||
class OfficeTextRenderer(TextRenderer):
|
||||
"""Uses Office's LucidaSans font for 32x32.
|
||||
|
||||
This font looks much better for certain strings (e.g. "PDF") but much worse
|
||||
for most others (e.g. "VIM", "JAVA") -- and office fonts are usually not
|
||||
installed. Hence, this class is better not used.
|
||||
"""
|
||||
|
||||
def _attribsAtSize(self, s):
|
||||
self.useOfficeFont = False
|
||||
attribs = TextRenderer._attribsAtSize(self, s)
|
||||
if s == 32:
|
||||
font = NSFont.fontWithName_size_('LucidaSans-Demi', 7.0)
|
||||
if font:
|
||||
attribs[NSFontAttributeName] = font
|
||||
attribs[NSKernAttributeName] = 0
|
||||
self.useOfficeFont = True
|
||||
return attribs
|
||||
|
||||
def drawTextAtSize(self, text, s):
|
||||
attribs = self.attribsAtSize(s)
|
||||
if not self.useOfficeFont or s != 32:
|
||||
TextRenderer.drawTextAtSize(self, text, s)
|
||||
return
|
||||
text = NSString.stringWithString_(text)
|
||||
text.drawInRect_withAttributes_( ((0, 1), (31, 11)), attribs)
|
||||
|
||||
|
||||
def createIcon(s, bg, textRenderer, text, shorttext=None):
|
||||
|
||||
# Fill in background
|
||||
output = bg.backgroundAtSize(s).copy()
|
||||
|
||||
# Draw text on top of shadow
|
||||
context = Context(output)
|
||||
if s in [16, 32] and shorttext:
|
||||
text = shorttext
|
||||
textRenderer.drawTextAtSize(text, s)
|
||||
context.done()
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def createLinks(icons, target):
|
||||
assert len(icons) > 0
|
||||
@@ -460,80 +116,75 @@ def createLinks(icons, target):
|
||||
os.symlink(target, icnsName)
|
||||
|
||||
|
||||
def saveIcns(icons, icnsName, makeIcns='./makeicns'):
|
||||
"""Creates an icns file with several variants.
|
||||
if not dont_create:
|
||||
# define a few classes to render custom 16x16 icons
|
||||
|
||||
Params:
|
||||
icons: A dict that contains icon size as key and Surface as value.
|
||||
Valid keys are 512, 256, 128, 32, 16
|
||||
icnsname: Name of the output file
|
||||
"""
|
||||
# XXX: Figure out how to call ObjC directly from Python, then this doesn't
|
||||
# need to call a different process and do lots of i/o.
|
||||
args = []
|
||||
for s, icon in icons.items():
|
||||
assert s in [512, 256, 128, 32, 16]
|
||||
assert icon.size() == [s, s]
|
||||
icon.save(TMPFILE % s)
|
||||
args.append('-%d %s' % (s, TMPFILE % s))
|
||||
os.system('%s %s -out %s' % (makeIcns, ' '.join(args), icnsName))
|
||||
class NoTextRenderer(docerator.TextRenderer):
|
||||
def drawTextAtSize(self, text, s):
|
||||
if s == 16: return # No text at 16x16
|
||||
docerator.TextRenderer.drawTextAtSize(self, text, s)
|
||||
|
||||
class NoIconRenderer(docerator.BackgroundRenderer):
|
||||
def drawIcon(self, s):
|
||||
if s == 16: return # no "MacVim" icon on the sheet at 16x16
|
||||
docerator.BackgroundRenderer.drawIcon(self, s)
|
||||
|
||||
class SmallTextRenderer(docerator.TextRenderer):
|
||||
def _attribsAtSize(self, s):
|
||||
attribs = docerator.TextRenderer._attribsAtSize(self, s)
|
||||
if s == 16:
|
||||
font = NSFont.fontWithName_size_('EnvyCodeR-Bold', 7.0)
|
||||
assert font
|
||||
attribs[NSFontAttributeName] = font
|
||||
attribs[NSForegroundColorAttributeName] = \
|
||||
NSColor.colorWithDeviceRed_green_blue_alpha_(
|
||||
0/255.0, 82/255.0, 0/255.0, 1)
|
||||
return attribs
|
||||
|
||||
def drawTextAtSize(self, text, s):
|
||||
if s != 16:
|
||||
docerator.TextRenderer.drawTextAtSize(self, text, s)
|
||||
return
|
||||
text = NSString.stringWithString_(text.lower()[0:3]) # at most 3 chars
|
||||
attribs = self.attribsAtSize(s)
|
||||
if len(text) <= 2:
|
||||
attribs[NSKernAttributeName] = 0 # we have some space
|
||||
else:
|
||||
attribs[NSKernAttributeName] = -1 # we need all the room we can get
|
||||
text.drawInRect_withAttributes_( ((1, 2), (15, 11)), attribs)
|
||||
|
||||
|
||||
TMPFILE = 'make_icons_tmp_%d.png'
|
||||
sizes = [512, 128, 32, 16]
|
||||
def main():
|
||||
if dont_create:
|
||||
print "PyObjC not found, only using a stock icon for document icons."
|
||||
# Can't use the constants from docerator in this case
|
||||
import shutil
|
||||
shutil.copyfile(DEFAULT_BACKGROUND, '%s.icns' % GENERIC_ICON_NAME)
|
||||
createLinks([name for name in vimIcons if name != GENERIC_ICON_NAME],
|
||||
'%s.icns' % GENERIC_ICON_NAME)
|
||||
return
|
||||
|
||||
srcdir = os.getcwd()
|
||||
if len(sys.argv) > 1:
|
||||
os.chdir(sys.argv[1])
|
||||
appIcon = os.path.join(srcdir, APPICON)
|
||||
makeIcns = os.path.join(srcdir, MAKEICNS)
|
||||
|
||||
if dont_create:
|
||||
print "PyObjC not found, only using a stock icon for document icons."
|
||||
import shutil
|
||||
shutil.copyfile(BACKGROUND, '%s.icns' % GENERIC_ICON_NAME)
|
||||
createLinks([name for name in vimIcons if name != GENERIC_ICON_NAME],
|
||||
'%s.icns' % GENERIC_ICON_NAME)
|
||||
return
|
||||
# Make us not crash
|
||||
# http://www.cocoabuilder.com/archive/message/cocoa/2008/8/6/214964
|
||||
NSApplicationLoad()
|
||||
|
||||
textRenderer = TextRenderer()
|
||||
#textRenderer = OfficeTextRenderer()
|
||||
|
||||
# Prepare input images
|
||||
bgIcon = Image(BACKGROUND)
|
||||
|
||||
#bg = SplittableBackground(bgIcon, shouldSplit=False)
|
||||
bg = SplittableBackground(bgIcon, shouldSplit=True)
|
||||
|
||||
icon = Image(appIcon)
|
||||
bgRenderer = BackgroundRenderer(bg, icon)
|
||||
|
||||
if not os.access(makeIcns, os.X_OK):
|
||||
print 'Cannot find makeicns at %s', makeIcns
|
||||
return
|
||||
|
||||
# create LARGE and SMALL icons first...
|
||||
for name, t in vimIcons.iteritems():
|
||||
text, size = t
|
||||
if size == LINK: continue
|
||||
print name
|
||||
icnsName = '%s.icns' % name
|
||||
|
||||
if size == SMALL:
|
||||
currSizes = [128, 32, 16]
|
||||
elif size == LARGE:
|
||||
currSizes = [512, 128, 32, 16]
|
||||
|
||||
st = shorttext.get(name)
|
||||
icons = [(s, createIcon(s, bgRenderer, textRenderer, text, shorttext=st))
|
||||
for s in currSizes]
|
||||
icons = dict(icons)
|
||||
saveIcns(icons, '%s.icns' % name, makeIcns)
|
||||
|
||||
del text, size, name, t
|
||||
if name == GENERIC_ICON_NAME:
|
||||
# The generic icon has no text; make the appicon a bit larger
|
||||
docerator.makedocicon(outname='%s.icns' % name, appicon=appIcon,
|
||||
text=text, sizes=iconsizes[size], makeicns=makeIcns,
|
||||
textrenderer=NoTextRenderer, rects={16:(0.0, 0.5533, 0.0, 0.5533)})
|
||||
else:
|
||||
# For the other icons, leave out appicon and render text in Envy Code R
|
||||
docerator.makedocicon(outname='%s.icns' % name, appicon=appIcon,
|
||||
text=text, sizes=iconsizes[size], makeicns=makeIcns,
|
||||
textrenderer=SmallTextRenderer, backgroundrenderer=NoIconRenderer)
|
||||
|
||||
# ...create links later (to make sure the link targets exist)
|
||||
createLinks([name for (name, t) in vimIcons.items() if t[1] == LINK],
|
||||
@@ -541,9 +192,4 @@ def main():
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
finally:
|
||||
for s in sizes:
|
||||
if os.access(TMPFILE % s, os.F_OK):
|
||||
os.remove(TMPFILE % s)
|
||||
|
||||
@@ -54,9 +54,10 @@ void usage() {
|
||||
NSBitmapImageRep* getBitmapImageRepOfSize(NSImage* img, int size) {
|
||||
|
||||
// Don't resample if it's not necessary
|
||||
// XXX: Seems as if this creates problems in some situations, disable this
|
||||
// for now.
|
||||
#if 0
|
||||
// IconFamily does not work correctly with
|
||||
// NSAlphaNonpremultipliedBitmapFormat images, so this has to stay disabled
|
||||
// until IconFamily is fixed (if ever).
|
||||
NSEnumerator* e = [[img representations] objectEnumerator];
|
||||
NSImageRep* ir;
|
||||
while ((ir = [e nextObject])) {
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
from distutils.core import setup, Extension
|
||||
|
||||
setup(name="loadfont", version="1.0",
|
||||
ext_modules = [Extension("loadfont", ["loadfont.c"])])
|
||||
|
||||
@@ -40,6 +40,123 @@
|
||||
Sparkle supports updates in zip, tar, tbz, tgz, or dmg format.
|
||||
-->
|
||||
|
||||
<item>
|
||||
<title>Snapshot 45 released</title>
|
||||
<description><![CDATA[
|
||||
<h1>MacVim snapshot 45 released</h1>
|
||||
|
||||
<p> Changes since snapshot 44:
|
||||
<ul>
|
||||
<li> The toolbar is not hidden by default again (if you prefer having the toolbar hidden, then add the line "set go-=T" to your ~/.gvimrc file) </li>
|
||||
<li> The ATSUI renderer honors the 'guisp' highlighting color </li>
|
||||
<li> Fix the forever bouncing Dock icon bug (Kazuki Sakamoto) </li>
|
||||
<li> Add the "Show Hidden Files" checkbox button to the Save dialog whenever the file browser is expanded </li>
|
||||
<li> Frontend refactoring </li>
|
||||
</ul>
|
||||
</p>
|
||||
]]></description>
|
||||
<pubDate>Mon, 13 Apr 2009 19:19 CET</pubDate>
|
||||
<enclosure type="application/octet-stream"
|
||||
url="http://newmacvim.muskokamug.org/mirror/files/MacVim-snapshot-45.tbz"
|
||||
length="8135831"
|
||||
sparkle:version="45"
|
||||
sparkle:shortVersionString="7.2"
|
||||
/>
|
||||
</item>
|
||||
|
||||
|
||||
<item>
|
||||
<title>Snapshot 44 released</title>
|
||||
<description><![CDATA[
|
||||
<h1>MacVim snapshot 44 released</h1>
|
||||
|
||||
<p> Changes since snapshot 43:
|
||||
<ul>
|
||||
<li> The color table had many erroneous entries which have been corrected (Zvezdan Petkovic) </li>
|
||||
<li> Ctrl+tab works again </li>
|
||||
<li> Tab labels only show file tail by default to make them more legible (reset to default by adding "set guitablabel&" to .gvimrc) </li>
|
||||
<li> The number of columns does not change on ":set go+=rT" </li>
|
||||
<li> Fixed problems with view not maximizing when entering full-screen and the Dock was visible </li>
|
||||
<li> Fix various problems related to having windows on a screen that got unplugged (fixes Issue 162) </li>
|
||||
<li> Latest source code version and runtime files (e.g. the Python syntax file is fixed, fixes Issue 160) </li>
|
||||
</ul>
|
||||
</p>
|
||||
]]></description>
|
||||
<pubDate>Sun, 29 Mar 2009 16:56 CET</pubDate>
|
||||
<enclosure type="application/octet-stream"
|
||||
url="http://newmacvim.muskokamug.org/mirror/files/MacVim-snapshot-44.tbz"
|
||||
length="8139075"
|
||||
sparkle:version="44"
|
||||
sparkle:shortVersionString="7.2"
|
||||
/>
|
||||
</item>
|
||||
|
||||
|
||||
<item>
|
||||
<title>Snapshot 43 released</title>
|
||||
<description><![CDATA[
|
||||
<h1>MacVim snapshot 43 released</h1>
|
||||
|
||||
<p><b>The automatic updating feature is broken in snapshots 39 and 40. If the automatic updating never finishes extracting then you are affected by this bug and will have to upgrade manually. To do so, simply go to the <a href="http://code.google.com/p/macvim/wiki/Snapshot">Snapshot page</a> to download the latest version.</b></p>
|
||||
|
||||
<p> Changes since snapshot 42:
|
||||
<ul>
|
||||
<li> Do inclusive search when opening files (Jonathon Mah) </li>
|
||||
<li> Respect layout prefs when double-clicking an already open file </li>
|
||||
<li> Fix two minor memory leaks </li>
|
||||
<li> Ctrl-] works on German keyboard layout </li>
|
||||
<li> The .viminfo file is written on Cmd-q </li>
|
||||
<li> New 16x16 icons (Nico Weber) </li>
|
||||
<li> Untitled window again opens on reopen event if requested in prefs </li>
|
||||
<li> Fork earlier; fixes bug with 'autochdir', faster startup, "f" no longer supported in 'guioptions' </li>
|
||||
<li> Some other minor bug fixes </li>
|
||||
<li> Use latest runtime files and Vim patches </li>
|
||||
</ul>
|
||||
</p>
|
||||
]]></description>
|
||||
<pubDate>Fri, 20 Feb 2009 13:49 CET</pubDate>
|
||||
<enclosure type="application/octet-stream"
|
||||
url="http://newmacvim.muskokamug.org/mirror/files/MacVim-snapshot-43.tbz"
|
||||
length="8136440"
|
||||
sparkle:version="43"
|
||||
sparkle:shortVersionString="7.2"
|
||||
/>
|
||||
</item>
|
||||
|
||||
|
||||
<item>
|
||||
<title>Snapshot 42 released</title>
|
||||
<description><![CDATA[
|
||||
<h1>MacVim snapshot 42 released</h1>
|
||||
|
||||
<p><b>The automatic updating feature is broken in snapshots 39 and 40. If the automatic updating never finishes extracting then you are affected by this bug and will have to upgrade manually. To do so, simply go to the <a href="http://code.google.com/p/macvim/wiki/Snapshot">Snapshot page</a> to download the latest version.</b></p>
|
||||
|
||||
<p> Changes since snapshot 40:
|
||||
<ul>
|
||||
<li> The menu bar behaves better when using full-screen and switching Spaces (Nico Weber) </li>
|
||||
<li> Don't switch Spaces when using "mvim" on one Space and a MacVim window is open on another Space </li>
|
||||
<li> Add user default to toggle the "add tab" button on the tabline (to disable, enter "defaults org.vim.MacVim MMShowAddTabButton 0" in Terminal) </li>
|
||||
<li> Avoid the "Press ENTER..." prompt when dragging and dropping </li>
|
||||
<li> Faster startup (and shutdown, but you're not likely to notice that unless you are me ;-) </li>
|
||||
<li> Automatic updating works again </li>
|
||||
<li> Possible to interrupt external commands (e.g. you can Ctrl-C during a lenghty :grep now) </li>
|
||||
<li> The output from external commands is displayed "interactively" (i.e. you don't have to wait for the command to finish before any output is drawn; try ":!ls -l /usr/lib" and compare with snap 40 to see what I mean) </li>
|
||||
<li> Cmd-. sends SIGINT (so that if a Vim process is stuck you should always be able to interrupt it with Cmd-. even if Ctrl-C doesn't work) </li>
|
||||
<li> Fix crashing bug: e.g. with snap 40 if you go to the src/ folder of Vim and type ":grep a *.c" MacVim would crash </li>
|
||||
<li> Toggle loading of default font with user default MMLoadDefaultFont </li>
|
||||
</ul>
|
||||
</p>
|
||||
]]></description>
|
||||
<pubDate>Sat, 12 Jan 2009 16:12 CET</pubDate>
|
||||
<enclosure type="application/octet-stream"
|
||||
url="http://newmacvim.muskokamug.org/mirror/files/MacVim-snapshot-42.tbz"
|
||||
length="8131516"
|
||||
sparkle:version="42"
|
||||
sparkle:shortVersionString="7.2"
|
||||
/>
|
||||
</item>
|
||||
|
||||
|
||||
<item>
|
||||
<title>Snapshot 40 released</title>
|
||||
<description><![CDATA[
|
||||
|
||||
@@ -354,6 +354,9 @@ MSVCVER = 9.0
|
||||
!if "$(_NMAKE_VER)" == "9.00.21022.08"
|
||||
MSVCVER = 9.0
|
||||
!endif
|
||||
!if "$(_NMAKE_VER)" == "9.00.30729.01"
|
||||
MSVCVER = 9.0
|
||||
!endif
|
||||
!endif
|
||||
|
||||
# Abort bulding VIM if version of VC is unrecognised.
|
||||
|
||||
Vendored
+61
@@ -11565,6 +11565,67 @@ _ACEOF
|
||||
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:$LINENO: checking for working volatile" >&5
|
||||
$as_echo_n "checking for working volatile... " >&6; }
|
||||
if test "${ac_cv_c_volatile+set}" = set; then
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
volatile int x;
|
||||
int * volatile y = (int *) 0;
|
||||
return !x && !y;
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
rm -f conftest.$ac_objext
|
||||
if { (ac_try="$ac_compile"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
|
||||
$as_echo "$ac_try_echo") >&5
|
||||
(eval "$ac_compile") 2>conftest.er1
|
||||
ac_status=$?
|
||||
grep -v '^ *+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
$as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } && {
|
||||
test -z "$ac_c_werror_flag" ||
|
||||
test ! -s conftest.err
|
||||
} && test -s conftest.$ac_objext; then
|
||||
ac_cv_c_volatile=yes
|
||||
else
|
||||
$as_echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
ac_cv_c_volatile=no
|
||||
fi
|
||||
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
fi
|
||||
{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_volatile" >&5
|
||||
$as_echo "$ac_cv_c_volatile" >&6; }
|
||||
if test $ac_cv_c_volatile = no; then
|
||||
|
||||
cat >>confdefs.h <<\_ACEOF
|
||||
#define volatile /**/
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:$LINENO: checking for mode_t" >&5
|
||||
$as_echo_n "checking for mode_t... " >&6; }
|
||||
if test "${ac_cv_type_mode_t+set}" = set; then
|
||||
|
||||
+6
-11
@@ -437,10 +437,6 @@ close_buffer(win, buf, action)
|
||||
return;
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_NETBEANS_INTG
|
||||
if (usingNetbeans)
|
||||
netbeans_file_closed(buf);
|
||||
#endif
|
||||
#ifdef FEAT_ODB_EDITOR
|
||||
odb_buffer_close(buf);
|
||||
#endif
|
||||
@@ -643,6 +639,10 @@ free_buffer_stuff(buf, free_options)
|
||||
#ifdef FEAT_SIGNS
|
||||
buf_delete_signs(buf); /* delete any signs */
|
||||
#endif
|
||||
#ifdef FEAT_NETBEANS_INTG
|
||||
if (usingNetbeans)
|
||||
netbeans_file_killed(buf);
|
||||
#endif
|
||||
#ifdef FEAT_LOCALMAP
|
||||
map_clear_int(buf, MAP_ALL_MODES, TRUE, FALSE); /* clear local mappings */
|
||||
map_clear_int(buf, MAP_ALL_MODES, TRUE, TRUE); /* clear local abbrevs */
|
||||
@@ -819,9 +819,6 @@ do_bufdel(command, arg, addr_count, start_bnr, end_bnr, forceit)
|
||||
int bnr; /* buffer number */
|
||||
char_u *p;
|
||||
|
||||
#ifdef FEAT_NETBEANS_INTG
|
||||
netbeansCloseFile = 1;
|
||||
#endif
|
||||
if (addr_count == 0)
|
||||
{
|
||||
(void)do_buffer(command, DOBUF_CURRENT, FORWARD, 0, forceit);
|
||||
@@ -916,9 +913,6 @@ do_bufdel(command, arg, addr_count, start_bnr, end_bnr, forceit)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FEAT_NETBEANS_INTG
|
||||
netbeansCloseFile = 0;
|
||||
#endif
|
||||
|
||||
return errormsg;
|
||||
}
|
||||
@@ -5114,7 +5108,8 @@ buf_spname(buf)
|
||||
*/
|
||||
FOR_ALL_TAB_WINDOWS(tp, win)
|
||||
if (win->w_buffer == buf)
|
||||
break;
|
||||
goto win_found;
|
||||
win_found:
|
||||
if (win != NULL && win->w_llist_ref != NULL)
|
||||
return _("[Location List]");
|
||||
else
|
||||
|
||||
@@ -50,6 +50,9 @@
|
||||
/* Define to empty if the keyword does not work. */
|
||||
#undef const
|
||||
|
||||
/* Define to empty if the keyword does not work. */
|
||||
#undef volatile
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
#undef mode_t
|
||||
|
||||
|
||||
@@ -2184,6 +2184,7 @@ fi
|
||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_PROG_GCC_TRADITIONAL
|
||||
AC_C_CONST
|
||||
AC_C_VOLATILE
|
||||
AC_TYPE_MODE_T
|
||||
AC_TYPE_OFF_T
|
||||
AC_TYPE_PID_T
|
||||
|
||||
+6
-4
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* diff.c: code for diff'ing two or three buffers.
|
||||
* diff.c: code for diff'ing two, three or four buffers.
|
||||
*/
|
||||
|
||||
#include "vim.h"
|
||||
@@ -116,7 +116,7 @@ diff_buf_adjust(win)
|
||||
* Add a buffer to make diffs for.
|
||||
* Call this when a new buffer is being edited in the current window where
|
||||
* 'diff' is set.
|
||||
* Marks the current buffer as being part of the diff and requireing updating.
|
||||
* Marks the current buffer as being part of the diff and requiring updating.
|
||||
* This must be done before any autocmd, because a command may use info
|
||||
* about the screen contents.
|
||||
*/
|
||||
@@ -929,7 +929,7 @@ ex_diffpatch(eap)
|
||||
goto theend;
|
||||
|
||||
#ifdef UNIX
|
||||
/* Temporaraly chdir to /tmp, to avoid patching files in the current
|
||||
/* Temporarily chdir to /tmp, to avoid patching files in the current
|
||||
* directory when the patch file contains more than one patch. When we
|
||||
* have our own temp dir use that instead, it will be cleaned up when we
|
||||
* exit (any .rej files created). Don't change directory if we can't
|
||||
@@ -1153,7 +1153,7 @@ ex_diffoff(eap)
|
||||
|
||||
for (wp = firstwin; wp != NULL; wp = wp->w_next)
|
||||
{
|
||||
if (wp == curwin || eap->forceit)
|
||||
if (wp == curwin || (eap->forceit && wp->w_p_diff))
|
||||
{
|
||||
/* Set 'diff', 'scrollbind' off and 'wrap' on. */
|
||||
wp->w_p_diff = FALSE;
|
||||
@@ -2129,6 +2129,8 @@ ex_diffgetput(eap)
|
||||
EMSG2(_("E102: Can't find buffer \"%s\""), eap->arg);
|
||||
return;
|
||||
}
|
||||
if (buf == curbuf)
|
||||
return; /* nothing to do */
|
||||
idx_other = diff_buf_idx(buf);
|
||||
if (idx_other == DB_COUNT)
|
||||
{
|
||||
|
||||
+77
-24
@@ -147,6 +147,7 @@ static void ins_compl_clear __ARGS((void));
|
||||
static int ins_compl_bs __ARGS((void));
|
||||
static void ins_compl_new_leader __ARGS((void));
|
||||
static void ins_compl_addleader __ARGS((int c));
|
||||
static int ins_compl_len __ARGS((void));
|
||||
static void ins_compl_restart __ARGS((void));
|
||||
static void ins_compl_set_original_text __ARGS((char_u *str));
|
||||
static void ins_compl_addfrommatch __ARGS((void));
|
||||
@@ -197,7 +198,8 @@ static void replace_pop_ins __ARGS((void));
|
||||
static void mb_replace_pop_ins __ARGS((int cc));
|
||||
#endif
|
||||
static void replace_flush __ARGS((void));
|
||||
static void replace_do_bs __ARGS((void));
|
||||
static void replace_do_bs __ARGS((int limit_col));
|
||||
static int del_char_after_col __ARGS((int limit_col));
|
||||
#ifdef FEAT_CINDENT
|
||||
static int cindent_on __ARGS((void));
|
||||
#endif
|
||||
@@ -1933,6 +1935,8 @@ truncate_spaces(line)
|
||||
/*
|
||||
* Backspace the cursor until the given column. Handles REPLACE and VREPLACE
|
||||
* modes correctly. May also be used when not in insert mode at all.
|
||||
* Will attempt not to go before "col" even when there is a composing
|
||||
* character.
|
||||
*/
|
||||
void
|
||||
backspace_until_column(col)
|
||||
@@ -1942,13 +1946,50 @@ backspace_until_column(col)
|
||||
{
|
||||
curwin->w_cursor.col--;
|
||||
if (State & REPLACE_FLAG)
|
||||
replace_do_bs();
|
||||
else
|
||||
(void)del_char(FALSE);
|
||||
replace_do_bs(col);
|
||||
else if (!del_char_after_col(col))
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Like del_char(), but make sure not to go before column "limit_col".
|
||||
* Only matters when there are composing characters.
|
||||
* Return TRUE when something was deleted.
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
static int
|
||||
del_char_after_col(limit_col)
|
||||
int limit_col;
|
||||
{
|
||||
#ifdef FEAT_MBYTE
|
||||
if (enc_utf8 && limit_col >= 0)
|
||||
{
|
||||
int ecol = curwin->w_cursor.col + 1;
|
||||
|
||||
/* Make sure the cursor is at the start of a character, but
|
||||
* skip forward again when going too far back because of a
|
||||
* composing character. */
|
||||
mb_adjust_cursor();
|
||||
while (curwin->w_cursor.col < (colnr_T)limit_col)
|
||||
{
|
||||
int l = utf_ptr2len(ml_get_cursor());
|
||||
|
||||
if (l == 0) /* end of line */
|
||||
break;
|
||||
curwin->w_cursor.col += l;
|
||||
}
|
||||
if (*ml_get_cursor() == NUL || curwin->w_cursor.col == ecol)
|
||||
return FALSE;
|
||||
del_bytes((long)(ecol - curwin->w_cursor.col), FALSE, TRUE);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
(void)del_char(FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if defined(FEAT_INS_EXPAND) || defined(PROTO)
|
||||
/*
|
||||
* CTRL-X pressed in Insert mode.
|
||||
@@ -2418,7 +2459,7 @@ ins_compl_longest_match(match)
|
||||
{
|
||||
had_match = (curwin->w_cursor.col > compl_col);
|
||||
ins_compl_delete();
|
||||
ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
|
||||
ins_bytes(compl_leader + ins_compl_len());
|
||||
ins_redraw(FALSE);
|
||||
|
||||
/* When the match isn't there (to avoid matching itself) remove it
|
||||
@@ -2470,7 +2511,7 @@ ins_compl_longest_match(match)
|
||||
*p = NUL;
|
||||
had_match = (curwin->w_cursor.col > compl_col);
|
||||
ins_compl_delete();
|
||||
ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
|
||||
ins_bytes(compl_leader + ins_compl_len());
|
||||
ins_redraw(FALSE);
|
||||
|
||||
/* When the match isn't there (to avoid matching itself) remove it
|
||||
@@ -3209,7 +3250,7 @@ ins_compl_new_leader()
|
||||
{
|
||||
ins_compl_del_pum();
|
||||
ins_compl_delete();
|
||||
ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
|
||||
ins_bytes(compl_leader + ins_compl_len());
|
||||
compl_used_match = FALSE;
|
||||
|
||||
if (compl_started)
|
||||
@@ -3263,6 +3304,20 @@ ins_compl_new_leader()
|
||||
compl_enter_selects = FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the length of the completion, from the completion start column to
|
||||
* the cursor column. Making sure it never goes below zero.
|
||||
*/
|
||||
static int
|
||||
ins_compl_len()
|
||||
{
|
||||
int off = curwin->w_cursor.col - compl_col;
|
||||
|
||||
if (off < 0)
|
||||
return 0;
|
||||
return off;
|
||||
}
|
||||
|
||||
/*
|
||||
* Append one character to the match leader. May reduce the number of
|
||||
* matches.
|
||||
@@ -3621,10 +3676,9 @@ ins_compl_prep(c)
|
||||
{
|
||||
ins_compl_delete();
|
||||
if (compl_leader != NULL)
|
||||
ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
|
||||
ins_bytes(compl_leader + ins_compl_len());
|
||||
else if (compl_first_match != NULL)
|
||||
ins_bytes(compl_orig_text
|
||||
+ curwin->w_cursor.col - compl_col);
|
||||
ins_bytes(compl_orig_text + ins_compl_len());
|
||||
retval = TRUE;
|
||||
}
|
||||
|
||||
@@ -4187,7 +4241,7 @@ ins_compl_get_exp(ini)
|
||||
}
|
||||
|
||||
/* check if compl_curr_match has changed, (e.g. other type of
|
||||
* expansion added somenthing) */
|
||||
* expansion added something) */
|
||||
if (type != 0 && compl_curr_match != old_match)
|
||||
found_new_match = OK;
|
||||
|
||||
@@ -4256,7 +4310,7 @@ ins_compl_delete()
|
||||
static void
|
||||
ins_compl_insert()
|
||||
{
|
||||
ins_bytes(compl_shown_match->cp_str + curwin->w_cursor.col - compl_col);
|
||||
ins_bytes(compl_shown_match->cp_str + ins_compl_len());
|
||||
if (compl_shown_match->cp_flags & ORIGINAL_TEXT)
|
||||
compl_used_match = FALSE;
|
||||
else
|
||||
@@ -4425,7 +4479,7 @@ ins_compl_next(allow_get_expansion, count, insert_match)
|
||||
if (!compl_get_longest || compl_used_match)
|
||||
ins_compl_insert();
|
||||
else
|
||||
ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
|
||||
ins_bytes(compl_leader + ins_compl_len());
|
||||
}
|
||||
else
|
||||
compl_used_match = FALSE;
|
||||
@@ -4688,7 +4742,7 @@ ins_complete(c)
|
||||
}
|
||||
compl_length = curwin->w_cursor.col - (int)compl_col;
|
||||
/* IObuff is used to add a "word from the next line" would we
|
||||
* have enough space? just being paranoic */
|
||||
* have enough space? just being paranoid */
|
||||
#define MIN_SPACE 75
|
||||
if (compl_length > (IOSIZE - MIN_SPACE))
|
||||
{
|
||||
@@ -7123,9 +7177,12 @@ replace_flush()
|
||||
* cc == 0: character was inserted, delete it
|
||||
* cc > 0: character was replaced, put cc (first byte of original char) back
|
||||
* and check for more characters to be put back
|
||||
* When "limit_col" is >= 0, don't delete before this column. Matters when
|
||||
* using composing characters, use del_char_after_col() instead of del_char().
|
||||
*/
|
||||
static void
|
||||
replace_do_bs()
|
||||
replace_do_bs(limit_col)
|
||||
int limit_col;
|
||||
{
|
||||
int cc;
|
||||
#ifdef FEAT_VREPLACE
|
||||
@@ -7153,7 +7210,7 @@ replace_do_bs()
|
||||
#ifdef FEAT_MBYTE
|
||||
if (has_mbyte)
|
||||
{
|
||||
del_char(FALSE);
|
||||
(void)del_char_after_col(limit_col);
|
||||
# ifdef FEAT_VREPLACE
|
||||
if (State & VREPLACE_FLAG)
|
||||
orig_len = (int)STRLEN(ml_get_cursor());
|
||||
@@ -7203,7 +7260,7 @@ replace_do_bs()
|
||||
changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col);
|
||||
}
|
||||
else if (cc == 0)
|
||||
(void)del_char(FALSE);
|
||||
(void)del_char_after_col(limit_col);
|
||||
}
|
||||
|
||||
#ifdef FEAT_CINDENT
|
||||
@@ -7646,9 +7703,7 @@ ins_reg()
|
||||
*/
|
||||
++no_mapping;
|
||||
regname = plain_vgetc();
|
||||
#ifdef FEAT_LANGMAP
|
||||
LANGMAP_ADJUST(regname, TRUE);
|
||||
#endif
|
||||
if (regname == Ctrl_R || regname == Ctrl_O || regname == Ctrl_P)
|
||||
{
|
||||
/* Get a third key for literal register insertion */
|
||||
@@ -7657,9 +7712,7 @@ ins_reg()
|
||||
add_to_showcmd_c(literally);
|
||||
#endif
|
||||
regname = plain_vgetc();
|
||||
#ifdef FEAT_LANGMAP
|
||||
LANGMAP_ADJUST(regname, TRUE);
|
||||
#endif
|
||||
}
|
||||
--no_mapping;
|
||||
|
||||
@@ -8150,7 +8203,7 @@ ins_ctrl_o()
|
||||
/*
|
||||
* If the cursor is on an indent, ^T/^D insert/delete one
|
||||
* shiftwidth. Otherwise ^T/^D behave like a "<<" or ">>".
|
||||
* Always round the indent to 'shiftwith', this is compatible
|
||||
* Always round the indent to 'shiftwidth', this is compatible
|
||||
* with vi. But vi only supports ^T and ^D after an
|
||||
* autoindent, we support it everywhere.
|
||||
*/
|
||||
@@ -8239,7 +8292,7 @@ ins_bs_one(vcolp)
|
||||
* Replace mode */
|
||||
if (curwin->w_cursor.lnum != Insstart.lnum
|
||||
|| curwin->w_cursor.col >= Insstart.col)
|
||||
replace_do_bs();
|
||||
replace_do_bs(-1);
|
||||
}
|
||||
else
|
||||
(void)del_char(FALSE);
|
||||
@@ -8556,7 +8609,7 @@ ins_bs(c, mode, inserted_space_p)
|
||||
break;
|
||||
}
|
||||
if (State & REPLACE_FLAG)
|
||||
replace_do_bs();
|
||||
replace_do_bs(-1);
|
||||
else
|
||||
{
|
||||
#ifdef FEAT_MBYTE
|
||||
|
||||
+9
-8
@@ -3928,7 +3928,7 @@ eval0(arg, rettv, nextcmd, evaluate)
|
||||
|
||||
/*
|
||||
* Handle top level expression:
|
||||
* expr1 ? expr0 : expr0
|
||||
* expr2 ? expr1 : expr1
|
||||
*
|
||||
* "arg" must point to the first non-white of the expression.
|
||||
* "arg" is advanced to the next non-white after the recognized expression.
|
||||
@@ -7918,9 +7918,9 @@ get_func_tv(name, len, rettv, arg, firstline, lastline, doesrange,
|
||||
else if (!aborting())
|
||||
{
|
||||
if (argcount == MAX_FUNC_ARGS)
|
||||
emsg_funcname("E740: Too many arguments for function %s", name);
|
||||
emsg_funcname(N_("E740: Too many arguments for function %s"), name);
|
||||
else
|
||||
emsg_funcname("E116: Invalid arguments for function %s", name);
|
||||
emsg_funcname(N_("E116: Invalid arguments for function %s"), name);
|
||||
}
|
||||
|
||||
while (--argcount >= 0)
|
||||
@@ -8153,6 +8153,7 @@ call_func(name, len, rettv, argcount, argvars, firstline, lastline,
|
||||
|
||||
/*
|
||||
* Give an error message with a function name. Handle <SNR> things.
|
||||
* "ermsg" is to be passed without translation, use N_() instead of _().
|
||||
*/
|
||||
static void
|
||||
emsg_funcname(ermsg, name)
|
||||
@@ -19887,7 +19888,7 @@ ex_function(eap)
|
||||
}
|
||||
}
|
||||
else
|
||||
emsg_funcname("E123: Undefined function: %s", name);
|
||||
emsg_funcname(N_("E123: Undefined function: %s"), name);
|
||||
}
|
||||
goto ret_free;
|
||||
}
|
||||
@@ -19931,7 +19932,7 @@ ex_function(eap)
|
||||
: eval_isnamec(arg[j])))
|
||||
++j;
|
||||
if (arg[j] != NUL)
|
||||
emsg_funcname(_(e_invarg2), arg);
|
||||
emsg_funcname((char *)e_invarg2, arg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20203,7 +20204,7 @@ ex_function(eap)
|
||||
v = find_var(name, &ht);
|
||||
if (v != NULL && v->di_tv.v_type == VAR_FUNC)
|
||||
{
|
||||
emsg_funcname("E707: Function name conflicts with variable: %s",
|
||||
emsg_funcname(N_("E707: Function name conflicts with variable: %s"),
|
||||
name);
|
||||
goto erret;
|
||||
}
|
||||
@@ -20218,7 +20219,7 @@ ex_function(eap)
|
||||
}
|
||||
if (fp->uf_calls > 0)
|
||||
{
|
||||
emsg_funcname("E127: Cannot redefine function %s: It is in use",
|
||||
emsg_funcname(N_("E127: Cannot redefine function %s: It is in use"),
|
||||
name);
|
||||
goto erret;
|
||||
}
|
||||
@@ -21497,7 +21498,7 @@ call_user_func(fp, argcount, argvars, rettv, firstline, lastline, selfdict)
|
||||
|
||||
/*
|
||||
* Return TRUE if items in "fc" do not have "copyID". That means they are not
|
||||
* referenced from anywyere.
|
||||
* referenced from anywhere.
|
||||
*/
|
||||
static int
|
||||
can_free_funccal(fc, copyID)
|
||||
|
||||
+51
-19
@@ -49,6 +49,7 @@ do_ascii(eap)
|
||||
exarg_T *eap;
|
||||
{
|
||||
int c;
|
||||
int cval;
|
||||
char buf1[20];
|
||||
char buf2[20];
|
||||
char_u buf3[7];
|
||||
@@ -75,6 +76,10 @@ do_ascii(eap)
|
||||
{
|
||||
if (c == NL) /* NUL is stored as NL */
|
||||
c = NUL;
|
||||
if (c == CAR && get_fileformat(curbuf) == EOL_MAC)
|
||||
cval = NL; /* NL is stored as CR */
|
||||
else
|
||||
cval = c;
|
||||
if (vim_isprintc_strict(c) && (c < ' '
|
||||
#ifndef EBCDIC
|
||||
|| c > '~'
|
||||
@@ -94,7 +99,7 @@ do_ascii(eap)
|
||||
buf2[0] = NUL;
|
||||
vim_snprintf((char *)IObuff, IOSIZE,
|
||||
_("<%s>%s%s %d, Hex %02x, Octal %03o"),
|
||||
transchar(c), buf1, buf2, c, c, c);
|
||||
transchar(c), buf1, buf2, cval, cval, cval);
|
||||
#ifdef FEAT_MBYTE
|
||||
if (enc_utf8)
|
||||
c = cc[ci++];
|
||||
@@ -2412,8 +2417,8 @@ print_line(lnum, use_number, list)
|
||||
cursor_on(); /* msg_start() switches it off */
|
||||
out_flush();
|
||||
silent_mode = save_silent;
|
||||
info_message = FALSE;
|
||||
}
|
||||
info_message = FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2702,7 +2707,12 @@ do_write(eap)
|
||||
if (eap->cmdidx == CMD_saveas)
|
||||
{
|
||||
if (retval == OK)
|
||||
{
|
||||
curbuf->b_p_ro = FALSE;
|
||||
#ifdef FEAT_WINDOWS
|
||||
redraw_tabline = TRUE;
|
||||
#endif
|
||||
}
|
||||
/* Change directories when the 'acd' option is set. */
|
||||
DO_AUTOCHDIR
|
||||
}
|
||||
@@ -6531,6 +6541,7 @@ static sign_T *first_sign = NULL;
|
||||
static int last_sign_typenr = MAX_TYPENR; /* is decremented */
|
||||
|
||||
static void sign_list_defined __ARGS((sign_T *sp));
|
||||
static void sign_undefine __ARGS((sign_T *sp, sign_T *sp_prev));
|
||||
|
||||
/*
|
||||
* ":sign" command
|
||||
@@ -6739,24 +6750,8 @@ ex_sign(eap)
|
||||
/* ":sign list {name}" */
|
||||
sign_list_defined(sp);
|
||||
else
|
||||
{
|
||||
/* ":sign undefine {name}" */
|
||||
vim_free(sp->sn_name);
|
||||
vim_free(sp->sn_icon);
|
||||
#ifdef FEAT_SIGN_ICONS
|
||||
if (sp->sn_image != NULL)
|
||||
{
|
||||
out_flush();
|
||||
gui_mch_destroy_sign(sp->sn_image);
|
||||
}
|
||||
#endif
|
||||
vim_free(sp->sn_text);
|
||||
if (sp_prev == NULL)
|
||||
first_sign = sp->sn_next;
|
||||
else
|
||||
sp_prev->sn_next = sp->sn_next;
|
||||
vim_free(sp);
|
||||
}
|
||||
sign_undefine(sp, sp_prev);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -7004,6 +6999,31 @@ sign_list_defined(sp)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Undefine a sign and free its memory.
|
||||
*/
|
||||
static void
|
||||
sign_undefine(sp, sp_prev)
|
||||
sign_T *sp;
|
||||
sign_T *sp_prev;
|
||||
{
|
||||
vim_free(sp->sn_name);
|
||||
vim_free(sp->sn_icon);
|
||||
#ifdef FEAT_SIGN_ICONS
|
||||
if (sp->sn_image != NULL)
|
||||
{
|
||||
out_flush();
|
||||
gui_mch_destroy_sign(sp->sn_image);
|
||||
}
|
||||
#endif
|
||||
vim_free(sp->sn_text);
|
||||
if (sp_prev == NULL)
|
||||
first_sign = sp->sn_next;
|
||||
else
|
||||
sp_prev->sn_next = sp->sn_next;
|
||||
vim_free(sp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get highlighting attribute for sign "typenr".
|
||||
* If "line" is TRUE: line highl, if FALSE: text highl.
|
||||
@@ -7078,6 +7098,18 @@ sign_typenr2name(typenr)
|
||||
return (char_u *)_("[Deleted]");
|
||||
}
|
||||
|
||||
#if defined(EXITFREE) || defined(PROTO)
|
||||
/*
|
||||
* Undefine/free all signs.
|
||||
*/
|
||||
void
|
||||
free_signs()
|
||||
{
|
||||
while (first_sign != NULL)
|
||||
sign_undefine(first_sign, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
|
||||
|
||||
+24
-19
@@ -2915,6 +2915,7 @@ do_source(fname, check_other, is_vimrc)
|
||||
linenr_T save_sourcing_lnum;
|
||||
char_u *p;
|
||||
char_u *fname_exp;
|
||||
char_u *firstline = NULL;
|
||||
int retval = FAIL;
|
||||
#ifdef FEAT_EVAL
|
||||
scid_T save_current_SID;
|
||||
@@ -3065,23 +3066,6 @@ do_source(fname, check_other, is_vimrc)
|
||||
|
||||
cookie.level = ex_nesting_level;
|
||||
#endif
|
||||
#ifdef FEAT_MBYTE
|
||||
cookie.conv.vc_type = CONV_NONE; /* no conversion */
|
||||
|
||||
/* Try reading the first few bytes to check for a UTF-8 BOM. */
|
||||
{
|
||||
char_u buf[3];
|
||||
|
||||
if (fread((char *)buf, sizeof(char_u), (size_t)3, cookie.fp)
|
||||
== (size_t)3
|
||||
&& buf[0] == 0xef && buf[1] == 0xbb && buf[2] == 0xbf)
|
||||
/* Found BOM, setup conversion and skip over it. */
|
||||
convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
|
||||
else
|
||||
/* No BOM found, rewind. */
|
||||
fseek(cookie.fp, 0L, SEEK_SET);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Keep the sourcing name/lnum, for recursive calls.
|
||||
@@ -3091,6 +3075,27 @@ do_source(fname, check_other, is_vimrc)
|
||||
save_sourcing_lnum = sourcing_lnum;
|
||||
sourcing_lnum = 0;
|
||||
|
||||
#ifdef FEAT_MBYTE
|
||||
cookie.conv.vc_type = CONV_NONE; /* no conversion */
|
||||
|
||||
/* Read the first line so we can check for a UTF-8 BOM. */
|
||||
firstline = getsourceline(0, (void *)&cookie, 0);
|
||||
if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
|
||||
&& firstline[1] == 0xbb && firstline[2] == 0xbf)
|
||||
{
|
||||
/* Found BOM; setup conversion, skip over BOM and recode the line. */
|
||||
convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
|
||||
p = string_convert(&cookie.conv, firstline + 3, NULL);
|
||||
if (p == NULL)
|
||||
p = vim_strsave(firstline + 3);
|
||||
if (p != NULL)
|
||||
{
|
||||
vim_free(firstline);
|
||||
firstline = p;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef STARTUPTIME
|
||||
time_push(&tv_rel, &tv_start);
|
||||
#endif
|
||||
@@ -3184,9 +3189,8 @@ do_source(fname, check_other, is_vimrc)
|
||||
/*
|
||||
* Call do_cmdline, which will call getsourceline() to get the lines.
|
||||
*/
|
||||
do_cmdline(NULL, getsourceline, (void *)&cookie,
|
||||
do_cmdline(firstline, getsourceline, (void *)&cookie,
|
||||
DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
|
||||
|
||||
retval = OK;
|
||||
|
||||
#ifdef FEAT_PROFILE
|
||||
@@ -3244,6 +3248,7 @@ almosttheend:
|
||||
#endif
|
||||
fclose(cookie.fp);
|
||||
vim_free(cookie.nextline);
|
||||
vim_free(firstline);
|
||||
#ifdef FEAT_MBYTE
|
||||
convert_setup(&cookie.conv, NULL, NULL);
|
||||
#endif
|
||||
|
||||
+65
-7
@@ -3690,6 +3690,11 @@ set_one_cmd_context(xp, buff)
|
||||
case CMD_highlight:
|
||||
set_context_in_highlight_cmd(xp, arg);
|
||||
break;
|
||||
#ifdef FEAT_CSCOPE
|
||||
case CMD_cscope:
|
||||
set_context_in_cscope_cmd(xp, arg);
|
||||
break;
|
||||
#endif
|
||||
#ifdef FEAT_LISTCMDS
|
||||
case CMD_bdelete:
|
||||
case CMD_bwipeout:
|
||||
@@ -5142,7 +5147,11 @@ uc_add_command(name, name_len, rep, argt, def, flags, compl, compl_arg, force)
|
||||
}
|
||||
|
||||
vim_free(cmd->uc_rep);
|
||||
cmd->uc_rep = 0;
|
||||
cmd->uc_rep = NULL;
|
||||
#if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL)
|
||||
vim_free(cmd->uc_compl_arg);
|
||||
cmd->uc_compl_arg = NULL;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5201,6 +5210,9 @@ static struct
|
||||
{EXPAND_AUGROUP, "augroup"},
|
||||
{EXPAND_BUFFERS, "buffer"},
|
||||
{EXPAND_COMMANDS, "command"},
|
||||
#if defined(FEAT_CSCOPE)
|
||||
{EXPAND_CSCOPE, "cscope"},
|
||||
#endif
|
||||
#if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL)
|
||||
{EXPAND_USER_DEFINED, "custom"},
|
||||
{EXPAND_USER_LIST, "customlist"},
|
||||
@@ -5500,6 +5512,9 @@ invalid_count:
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* ":command ..."
|
||||
*/
|
||||
static void
|
||||
ex_command(eap)
|
||||
exarg_T *eap;
|
||||
@@ -5931,7 +5946,8 @@ do_ucmd(eap)
|
||||
char_u *q;
|
||||
|
||||
char_u *start;
|
||||
char_u *end;
|
||||
char_u *end = NULL;
|
||||
char_u *ksp;
|
||||
size_t len, totlen;
|
||||
|
||||
size_t split_len = 0;
|
||||
@@ -5948,16 +5964,51 @@ do_ucmd(eap)
|
||||
|
||||
/*
|
||||
* Replace <> in the command by the arguments.
|
||||
* First round: "buf" is NULL, compute length, allocate "buf".
|
||||
* Second round: copy result into "buf".
|
||||
*/
|
||||
buf = NULL;
|
||||
for (;;)
|
||||
{
|
||||
p = cmd->uc_rep;
|
||||
q = buf;
|
||||
p = cmd->uc_rep; /* source */
|
||||
q = buf; /* destination */
|
||||
totlen = 0;
|
||||
while ((start = vim_strchr(p, '<')) != NULL
|
||||
&& (end = vim_strchr(start + 1, '>')) != NULL)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
start = vim_strchr(p, '<');
|
||||
if (start != NULL)
|
||||
end = vim_strchr(start + 1, '>');
|
||||
if (buf != NULL)
|
||||
{
|
||||
ksp = vim_strchr(p, K_SPECIAL);
|
||||
if (ksp != NULL && (start == NULL || ksp < start || end == NULL)
|
||||
&& ((ksp[1] == KS_SPECIAL && ksp[2] == KE_FILLER)
|
||||
# ifdef FEAT_GUI
|
||||
|| (ksp[1] == KS_EXTRA && ksp[2] == (int)KE_CSI)
|
||||
# endif
|
||||
))
|
||||
{
|
||||
/* K_SPECIAL han been put in the buffer as K_SPECIAL
|
||||
* KS_SPECIAL KE_FILLER, like for mappings, but
|
||||
* do_cmdline() doesn't handle that, so convert it back.
|
||||
* Also change K_SPECIAL KS_EXTRA KE_CSI into CSI. */
|
||||
len = ksp - p;
|
||||
if (len > 0)
|
||||
{
|
||||
mch_memmove(q, p, len);
|
||||
q += len;
|
||||
}
|
||||
*q++ = ksp[1] == KS_SPECIAL ? K_SPECIAL : CSI;
|
||||
p = ksp + 3;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* break if there no <item> is found */
|
||||
if (start == NULL || end == NULL)
|
||||
break;
|
||||
|
||||
/* Include the '>' */
|
||||
++end;
|
||||
|
||||
@@ -7827,6 +7878,9 @@ free_cd_dir()
|
||||
{
|
||||
vim_free(prev_dir);
|
||||
prev_dir = NULL;
|
||||
|
||||
vim_free(globaldir);
|
||||
globaldir = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -7849,6 +7903,10 @@ ex_cd(eap)
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef FEAT_AUTOCMD
|
||||
if (allbuf_locked())
|
||||
return;
|
||||
#endif
|
||||
if (vim_strchr(p_cpo, CPO_CHDIR) != NULL && curbufIsChanged()
|
||||
&& !eap->forceit)
|
||||
{
|
||||
@@ -8773,7 +8831,7 @@ ex_mkrc(eap)
|
||||
else if (*dirnow != NUL
|
||||
&& (ssop_flags & SSOP_CURDIR) && globaldir != NULL)
|
||||
{
|
||||
if (mch_chdir((char *)globaldir) == OK)
|
||||
if (mch_chdir((char *)globaldir) == 0)
|
||||
shorten_fnames(TRUE);
|
||||
}
|
||||
|
||||
|
||||
+22
-6
@@ -2000,8 +2000,8 @@ text_locked_msg()
|
||||
|
||||
#if defined(FEAT_AUTOCMD) || defined(PROTO)
|
||||
/*
|
||||
* Check if "curbuf_lock" is set and return TRUE when it is and give an error
|
||||
* message.
|
||||
* Check if "curbuf_lock" or "allbuf_lock" is set and return TRUE when it is
|
||||
* and give an error message.
|
||||
*/
|
||||
int
|
||||
curbuf_locked()
|
||||
@@ -2011,6 +2011,21 @@ curbuf_locked()
|
||||
EMSG(_("E788: Not allowed to edit another buffer now"));
|
||||
return TRUE;
|
||||
}
|
||||
return allbuf_locked();
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if "allbuf_lock" is set and return TRUE when it is and give an error
|
||||
* message.
|
||||
*/
|
||||
int
|
||||
allbuf_locked()
|
||||
{
|
||||
if (allbuf_lock > 0)
|
||||
{
|
||||
EMSG(_("E811: Not allowed to change buffer information now"));
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
@@ -4503,6 +4518,9 @@ ExpandFromContext(xp, pat, num_file, file, options)
|
||||
{EXPAND_EVENTS, get_event_name, TRUE},
|
||||
{EXPAND_AUGROUP, get_augroup_name, TRUE},
|
||||
#endif
|
||||
#ifdef FEAT_CSCOPE
|
||||
{EXPAND_CSCOPE, get_cscope_name, TRUE},
|
||||
#endif
|
||||
#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
|
||||
&& (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
|
||||
{EXPAND_LANGUAGE, get_lang_arg, TRUE},
|
||||
@@ -6050,9 +6068,7 @@ ex_window()
|
||||
# endif
|
||||
return K_IGNORE;
|
||||
}
|
||||
cmdwin_type = ccline.cmdfirstc;
|
||||
if (cmdwin_type == NUL)
|
||||
cmdwin_type = '-';
|
||||
cmdwin_type = get_cmdline_type();
|
||||
|
||||
/* Create the command-line buffer empty. */
|
||||
(void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, NULL);
|
||||
@@ -6076,7 +6092,7 @@ ex_window()
|
||||
/* Showing the prompt may have set need_wait_return, reset it. */
|
||||
need_wait_return = FALSE;
|
||||
|
||||
histtype = hist_char2type(ccline.cmdfirstc);
|
||||
histtype = hist_char2type(cmdwin_type);
|
||||
if (histtype == HIST_CMD || histtype == HIST_DEBUG)
|
||||
{
|
||||
if (p_wc == TAB)
|
||||
|
||||
+124
-9
@@ -69,7 +69,7 @@ static int apply_autocmds_exarg __ARGS((event_T event, char_u *fname, char_u *fn
|
||||
static int au_find_group __ARGS((char_u *name));
|
||||
|
||||
# define AUGROUP_DEFAULT -1 /* default autocmd group */
|
||||
# define AUGROUP_ERROR -2 /* errornouse autocmd group */
|
||||
# define AUGROUP_ERROR -2 /* erroneous autocmd group */
|
||||
# define AUGROUP_ALL -3 /* all autocmd groups */
|
||||
#endif
|
||||
|
||||
@@ -144,7 +144,9 @@ static int get_mac_fio_flags __ARGS((char_u *ptr));
|
||||
# endif
|
||||
#endif
|
||||
static int move_lines __ARGS((buf_T *frombuf, buf_T *tobuf));
|
||||
|
||||
#ifdef FEAT_AUTOCMD
|
||||
static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name");
|
||||
#endif
|
||||
|
||||
void
|
||||
filemess(buf, name, s, attr)
|
||||
@@ -295,6 +297,19 @@ readfile(fname, sfname, from, lines_to_skip, lines_to_read, eap, flags)
|
||||
int conv_restlen = 0; /* nr of bytes in conv_rest[] */
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_AUTOCMD
|
||||
/* Remember the initial values of curbuf, curbuf->b_ffname and
|
||||
* curbuf->b_fname to detect whether they are altered as a result of
|
||||
* executing nasty autocommands. Also check if "fname" and "sfname"
|
||||
* point to one of these values. */
|
||||
buf_T *old_curbuf = curbuf;
|
||||
char_u *old_b_ffname = curbuf->b_ffname;
|
||||
char_u *old_b_fname = curbuf->b_fname;
|
||||
int using_b_ffname = (fname == curbuf->b_ffname)
|
||||
|| (sfname == curbuf->b_ffname);
|
||||
int using_b_fname = (fname == curbuf->b_fname)
|
||||
|| (sfname == curbuf->b_fname);
|
||||
#endif
|
||||
write_no_eol_lnum = 0; /* in case it was set by the previous read */
|
||||
|
||||
/*
|
||||
@@ -589,7 +604,21 @@ readfile(fname, sfname, from, lines_to_skip, lines_to_read, eap, flags)
|
||||
#ifdef FEAT_QUICKFIX
|
||||
if (!bt_dontwrite(curbuf))
|
||||
#endif
|
||||
{
|
||||
check_need_swap(newfile);
|
||||
#ifdef FEAT_AUTOCMD
|
||||
/* SwapExists autocommand may mess things up */
|
||||
if (curbuf != old_curbuf
|
||||
|| (using_b_ffname
|
||||
&& (old_b_ffname != curbuf->b_ffname))
|
||||
|| (using_b_fname
|
||||
&& (old_b_fname != curbuf->b_fname)))
|
||||
{
|
||||
EMSG(_(e_auchangedbuf));
|
||||
return FAIL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (dir_of_file_exists(fname))
|
||||
filemess(curbuf, sfname, (char_u *)_("[New File]"), 0);
|
||||
else
|
||||
@@ -668,6 +697,17 @@ readfile(fname, sfname, from, lines_to_skip, lines_to_read, eap, flags)
|
||||
#endif
|
||||
{
|
||||
check_need_swap(newfile);
|
||||
#ifdef FEAT_AUTOCMD
|
||||
if (!read_stdin && (curbuf != old_curbuf
|
||||
|| (using_b_ffname && (old_b_ffname != curbuf->b_ffname))
|
||||
|| (using_b_fname && (old_b_fname != curbuf->b_fname))))
|
||||
{
|
||||
EMSG(_(e_auchangedbuf));
|
||||
if (!read_buffer)
|
||||
close(fd);
|
||||
return FAIL;
|
||||
}
|
||||
#endif
|
||||
#ifdef UNIX
|
||||
/* Set swap file protection bits after creating it. */
|
||||
if (swap_mode > 0 && curbuf->b_ml.ml_mfp->mf_fname != NULL)
|
||||
@@ -698,7 +738,6 @@ readfile(fname, sfname, from, lines_to_skip, lines_to_read, eap, flags)
|
||||
{
|
||||
int m = msg_scroll;
|
||||
int n = msg_scrolled;
|
||||
buf_T *old_curbuf = curbuf;
|
||||
|
||||
/*
|
||||
* The file must be closed again, the autocommands may want to change
|
||||
@@ -740,8 +779,13 @@ readfile(fname, sfname, from, lines_to_skip, lines_to_read, eap, flags)
|
||||
/*
|
||||
* Don't allow the autocommands to change the current buffer.
|
||||
* Try to re-open the file.
|
||||
*
|
||||
* Don't allow the autocommands to change the buffer name either
|
||||
* (cd for example) if it invalidates fname or sfname.
|
||||
*/
|
||||
if (!read_stdin && (curbuf != old_curbuf
|
||||
|| (using_b_ffname && (old_b_ffname != curbuf->b_ffname))
|
||||
|| (using_b_fname && (old_b_fname != curbuf->b_fname))
|
||||
|| (fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) < 0))
|
||||
{
|
||||
--no_wait_return;
|
||||
@@ -5248,13 +5292,16 @@ buf_write_bytes(ip)
|
||||
/* Convert with iconv(). */
|
||||
if (ip->bw_restlen > 0)
|
||||
{
|
||||
char *fp;
|
||||
|
||||
/* Need to concatenate the remainder of the previous call and
|
||||
* the bytes of the current call. Use the end of the
|
||||
* conversion buffer for this. */
|
||||
fromlen = len + ip->bw_restlen;
|
||||
from = (char *)ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
|
||||
mch_memmove((void *)from, ip->bw_rest, (size_t)ip->bw_restlen);
|
||||
mch_memmove((void *)(from + ip->bw_restlen), buf, (size_t)len);
|
||||
fp = (char *)ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
|
||||
mch_memmove(fp, ip->bw_rest, (size_t)ip->bw_restlen);
|
||||
mch_memmove(fp + ip->bw_restlen, buf, (size_t)len);
|
||||
from = fp;
|
||||
tolen = ip->bw_conv_buflen - fromlen;
|
||||
}
|
||||
else
|
||||
@@ -6111,12 +6158,24 @@ vim_rename(from, to)
|
||||
#ifdef HAVE_ACL
|
||||
vim_acl_T acl; /* ACL from original file */
|
||||
#endif
|
||||
#if defined(UNIX) || defined(CASE_INSENSITIVE_FILENAME)
|
||||
int use_tmp_file = FALSE;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* When the names are identical, there is nothing to do.
|
||||
* When the names are identical, there is nothing to do. When they refer
|
||||
* to the same file (ignoring case and slash/backslash differences) but
|
||||
* the file name differs we need to go through a temp file.
|
||||
*/
|
||||
if (fnamecmp(from, to) == 0)
|
||||
return 0;
|
||||
{
|
||||
#ifdef CASE_INSENSITIVE_FILENAME
|
||||
if (STRCMP(gettail(from), gettail(to)) != 0)
|
||||
use_tmp_file = TRUE;
|
||||
else
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fail if the "from" file doesn't exist. Avoids that "to" is deleted.
|
||||
@@ -6124,6 +6183,55 @@ vim_rename(from, to)
|
||||
if (mch_stat((char *)from, &st) < 0)
|
||||
return -1;
|
||||
|
||||
#ifdef UNIX
|
||||
{
|
||||
struct stat st_to;
|
||||
|
||||
/* It's possible for the source and destination to be the same file.
|
||||
* This happens when "from" and "to" differ in case and are on a FAT32
|
||||
* filesystem. In that case go through a temp file name. */
|
||||
if (mch_stat((char *)to, &st_to) >= 0
|
||||
&& st.st_dev == st_to.st_dev
|
||||
&& st.st_ino == st_to.st_ino)
|
||||
use_tmp_file = TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(UNIX) || defined(CASE_INSENSITIVE_FILENAME)
|
||||
if (use_tmp_file)
|
||||
{
|
||||
char tempname[MAXPATHL + 1];
|
||||
|
||||
/*
|
||||
* Find a name that doesn't exist and is in the same directory.
|
||||
* Rename "from" to "tempname" and then rename "tempname" to "to".
|
||||
*/
|
||||
if (STRLEN(from) >= MAXPATHL - 5)
|
||||
return -1;
|
||||
STRCPY(tempname, from);
|
||||
for (n = 123; n < 99999; ++n)
|
||||
{
|
||||
sprintf((char *)gettail((char_u *)tempname), "%d", n);
|
||||
if (mch_stat(tempname, &st) < 0)
|
||||
{
|
||||
if (mch_rename((char *)from, tempname) == 0)
|
||||
{
|
||||
if (mch_rename(tempname, (char *)to) == 0)
|
||||
return 0;
|
||||
/* Strange, the second step failed. Try moving the
|
||||
* file back and return failure. */
|
||||
mch_rename(tempname, (char *)from);
|
||||
return -1;
|
||||
}
|
||||
/* If it fails for one temp name it will most likely fail
|
||||
* for any temp name, give up. */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Delete the "to" file, this is required on some systems to make the
|
||||
* mch_rename() work, on other systems it makes sure that we don't have
|
||||
@@ -6267,7 +6375,7 @@ check_timestamps(focus)
|
||||
|
||||
if (!stuff_empty() || global_busy || !typebuf_typed()
|
||||
#ifdef FEAT_AUTOCMD
|
||||
|| autocmd_busy || curbuf_lock > 0
|
||||
|| autocmd_busy || curbuf_lock > 0 || allbuf_lock > 0
|
||||
#endif
|
||||
)
|
||||
need_check_timestamps = TRUE; /* check later */
|
||||
@@ -6475,8 +6583,10 @@ buf_check_timestamp(buf, focus)
|
||||
set_vim_var_string(VV_FCS_REASON, (char_u *)reason, -1);
|
||||
set_vim_var_string(VV_FCS_CHOICE, (char_u *)"", -1);
|
||||
# endif
|
||||
++allbuf_lock;
|
||||
n = apply_autocmds(EVENT_FILECHANGEDSHELL,
|
||||
buf->b_fname, buf->b_fname, FALSE, buf);
|
||||
--allbuf_lock;
|
||||
busy = FALSE;
|
||||
if (n)
|
||||
{
|
||||
@@ -6551,6 +6661,11 @@ buf_check_timestamp(buf, focus)
|
||||
tbuf = alloc((unsigned)(STRLEN(path) + STRLEN(mesg)
|
||||
+ STRLEN(mesg2) + 2));
|
||||
sprintf((char *)tbuf, mesg, path);
|
||||
#ifdef FEAT_EVAL
|
||||
/* Set warningmsg here, before the unimportant and output-specific
|
||||
* mesg2 has been appended. */
|
||||
set_vim_var_string(VV_WARNINGMSG, tbuf, -1);
|
||||
#endif
|
||||
#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
|
||||
if (can_reload)
|
||||
{
|
||||
|
||||
+12
-6
@@ -740,7 +740,7 @@ deleteFold(start, end, recursive, had_visual)
|
||||
garray_T *found_ga;
|
||||
fold_T *found_fp = NULL;
|
||||
linenr_T found_off = 0;
|
||||
int use_level = FALSE;
|
||||
int use_level;
|
||||
int maybe_small = FALSE;
|
||||
int level = 0;
|
||||
linenr_T lnum = start;
|
||||
@@ -757,6 +757,7 @@ deleteFold(start, end, recursive, had_visual)
|
||||
gap = &curwin->w_folds;
|
||||
found_ga = NULL;
|
||||
lnum_off = 0;
|
||||
use_level = FALSE;
|
||||
for (;;)
|
||||
{
|
||||
if (!foldFind(gap, lnum - lnum_off, &fp))
|
||||
@@ -783,20 +784,21 @@ deleteFold(start, end, recursive, had_visual)
|
||||
else
|
||||
{
|
||||
lnum = found_fp->fd_top + found_fp->fd_len + found_off;
|
||||
did_one = TRUE;
|
||||
|
||||
if (foldmethodIsManual(curwin))
|
||||
deleteFoldEntry(found_ga,
|
||||
(int)(found_fp - (fold_T *)found_ga->ga_data), recursive);
|
||||
else
|
||||
{
|
||||
if (found_fp->fd_top + found_off < first_lnum)
|
||||
first_lnum = found_fp->fd_top;
|
||||
if (lnum > last_lnum)
|
||||
if (first_lnum > found_fp->fd_top + found_off)
|
||||
first_lnum = found_fp->fd_top + found_off;
|
||||
if (last_lnum < lnum)
|
||||
last_lnum = lnum;
|
||||
parseMarker(curwin);
|
||||
if (!did_one)
|
||||
parseMarker(curwin);
|
||||
deleteFoldMarkers(found_fp, recursive, found_off);
|
||||
}
|
||||
did_one = TRUE;
|
||||
|
||||
/* redraw window */
|
||||
changed_window_setting();
|
||||
@@ -811,6 +813,10 @@ deleteFold(start, end, recursive, had_visual)
|
||||
redraw_curbuf_later(INVERTED);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
/* Deleting markers may make cursor column invalid. */
|
||||
check_cursor_col();
|
||||
|
||||
if (last_lnum > 0)
|
||||
changed_lines(first_lnum, (colnr_T)0, last_lnum, 0L);
|
||||
}
|
||||
|
||||
@@ -3816,7 +3816,11 @@ showmap(mp, local)
|
||||
int len = 1;
|
||||
|
||||
if (msg_didout || msg_silent != 0)
|
||||
{
|
||||
msg_putchar('\n');
|
||||
if (got_int) /* 'q' typed at MORE prompt */
|
||||
return;
|
||||
}
|
||||
if ((mp->m_mode & (INSERT + CMDLINE)) == INSERT + CMDLINE)
|
||||
msg_putchar('!'); /* :map! */
|
||||
else if (mp->m_mode & INSERT)
|
||||
|
||||
+17
-7
@@ -482,8 +482,10 @@ EXTERN char *foreground_argument INIT(= NULL);
|
||||
/*
|
||||
* While executing external commands or in Ex mode, should not insert GUI
|
||||
* events in the input buffer: Set hold_gui_events to non-zero.
|
||||
*
|
||||
* volatile because it is used in signal handler sig_sysmouse().
|
||||
*/
|
||||
EXTERN int hold_gui_events INIT(= 0);
|
||||
EXTERN volatile int hold_gui_events INIT(= 0);
|
||||
|
||||
/*
|
||||
* When resizing the shell is postponed, remember the new size, and call
|
||||
@@ -597,7 +599,8 @@ EXTERN int exiting INIT(= FALSE);
|
||||
EXTERN int really_exiting INIT(= FALSE);
|
||||
/* TRUE when we are sure to exit, e.g., after
|
||||
* a deadly signal */
|
||||
EXTERN int full_screen INIT(= FALSE);
|
||||
/* volatile because it is used in signal handler deathtrap(). */
|
||||
EXTERN volatile int full_screen INIT(= FALSE);
|
||||
/* TRUE when doing full-screen output
|
||||
* otherwise only writing some messages */
|
||||
|
||||
@@ -616,6 +619,11 @@ EXTERN int textlock INIT(= 0);
|
||||
EXTERN int curbuf_lock INIT(= 0);
|
||||
/* non-zero when the current buffer can't be
|
||||
* changed. Used for FileChangedRO. */
|
||||
EXTERN int allbuf_lock INIT(= 0);
|
||||
/* non-zero when no buffer name can be
|
||||
* changed, no buffer can be deleted and
|
||||
* current directory can't be changed.
|
||||
* Used for SwapExists et al. */
|
||||
#endif
|
||||
#ifdef FEAT_EVAL
|
||||
# define HAVE_SANDBOX
|
||||
@@ -739,10 +747,12 @@ EXTERN JMP_BUF x_jump_env;
|
||||
*/
|
||||
EXTERN JMP_BUF lc_jump_env; /* argument to SETJMP() */
|
||||
# ifdef SIGHASARG
|
||||
EXTERN int lc_signal; /* catched signal number, 0 when no was signal
|
||||
catched; used for mch_libcall() */
|
||||
/* volatile because it is used in signal handlers. */
|
||||
EXTERN volatile int lc_signal; /* caught signal number, 0 when no was signal
|
||||
caught; used for mch_libcall() */
|
||||
# endif
|
||||
EXTERN int lc_active INIT(= FALSE); /* TRUE when lc_jump_env is valid. */
|
||||
/* volatile because it is used in signal handler deathtrap(). */
|
||||
EXTERN volatile int lc_active INIT(= FALSE); /* TRUE when lc_jump_env is valid. */
|
||||
#endif
|
||||
|
||||
#if defined(FEAT_MBYTE) || defined(FEAT_POSTSCRIPT)
|
||||
@@ -986,7 +996,8 @@ EXTERN int curscript INIT(= 0); /* index in scriptin[] */
|
||||
EXTERN FILE *scriptout INIT(= NULL); /* stream to write script to */
|
||||
EXTERN int read_cmd_fd INIT(= 0); /* fd to read commands from */
|
||||
|
||||
EXTERN int got_int INIT(= FALSE); /* set to TRUE when interrupt
|
||||
/* volatile because it is used in signal handler catch_sigint(). */
|
||||
EXTERN volatile int got_int INIT(= FALSE); /* set to TRUE when interrupt
|
||||
signal occurred */
|
||||
#ifdef USE_TERM_CONSOLE
|
||||
EXTERN int term_console INIT(= FALSE); /* set to TRUE when console used */
|
||||
@@ -1342,7 +1353,6 @@ EXTERN garray_T error_ga
|
||||
|
||||
#ifdef FEAT_NETBEANS_INTG
|
||||
EXTERN char *netbeansArg INIT(= NULL); /* the -nb[:host:port:passwd] arg */
|
||||
EXTERN int netbeansCloseFile INIT(= 0); /* send killed if != 0 */
|
||||
EXTERN int netbeansFireChanges INIT(= 1); /* send buffer changes if != 0 */
|
||||
EXTERN int netbeansForcedQuit INIT(= 0);/* don't write modified files */
|
||||
EXTERN int netbeansReadFile INIT(= 1); /* OK to read from disk if != 0 */
|
||||
|
||||
@@ -58,7 +58,11 @@ static int can_update_cursor = TRUE; /* can display the cursor */
|
||||
gui_start()
|
||||
{
|
||||
char_u *old_term;
|
||||
#if defined(UNIX) && !defined(__BEOS__)
|
||||
#if defined(UNIX) && !defined(__BEOS__) && !defined(MACOS_X)
|
||||
/* By the time we get here Mac OS X will already have forked (it does so
|
||||
* right after scanning the command line) so don't do anything here. This
|
||||
* means that "f" in 'guioptions' cannot be supported.
|
||||
*/
|
||||
# define MAY_FORK
|
||||
int dofork = TRUE;
|
||||
#endif
|
||||
@@ -117,82 +121,10 @@ gui_start()
|
||||
*/
|
||||
if (gui.in_use && dofork)
|
||||
{
|
||||
pid_t pid = -1;
|
||||
|
||||
# if defined MACOS_X
|
||||
int i;
|
||||
|
||||
/* on os x, you have to exec after a fork, otherwise calls to
|
||||
* frameworks will assert (and without corefoundation, you can't start
|
||||
* the gui. what fun.). See CAVEATS at
|
||||
http://developer.apple.com/documentation/Darwin/Reference/ManPages/man2/fork.2.html
|
||||
*
|
||||
* Since we have to go through this anyways, we might as well use vfork.
|
||||
* But: then we can't detach from our starting shell, so stick with
|
||||
* fork.
|
||||
*
|
||||
* Kinda sucks to restart vim when doing :gui, so don't fork in that
|
||||
* case (make sure gui.dofork is only set when interpreting argv, not
|
||||
* when doing :gui. Currently, gui.dofork is set to false in ex_gui().
|
||||
*
|
||||
* Also doesn't work well if vim starts cscope (or some other
|
||||
* subprocess I guess), because it's not transferred to the newly
|
||||
* exec'd process, leaving an orphaned process (not a zombie process)
|
||||
* behind. The Right Thing is to kill all our child processes before
|
||||
* calling exec.
|
||||
*/
|
||||
|
||||
/* stolen from http://paste.lisp.org/display/50906 */
|
||||
extern int *_NSGetArgc(void);
|
||||
extern char ***_NSGetArgv(void);
|
||||
|
||||
int argc = *_NSGetArgc();
|
||||
char ** argv = *_NSGetArgv();
|
||||
char * newargv[argc+2];
|
||||
|
||||
newargv[0] = argv[0];
|
||||
|
||||
/*
|
||||
* make sure "-f" is in front of potential "--remote" flags, else
|
||||
* they would consume it.
|
||||
*/
|
||||
newargv[1] = "-f";
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
newargv[i + 1] = argv[i];
|
||||
}
|
||||
newargv[argc+1] = NULL;
|
||||
|
||||
/* shut down all the stuff we just started, just to start
|
||||
* it again from the exec :-\ */
|
||||
prepare_getout();
|
||||
|
||||
pid = fork();
|
||||
switch(pid) {
|
||||
case -1:
|
||||
# ifndef NDEBUG
|
||||
fprintf(stderr, "vim: Mac OS X workaround fork() failed!");
|
||||
# endif
|
||||
_exit(255);
|
||||
case 0:
|
||||
/* Child. */
|
||||
|
||||
/* make sure we survive our shell */
|
||||
setsid();
|
||||
|
||||
/* Restarts the vim process, will not return. */
|
||||
execvp(argv[0], newargv);
|
||||
|
||||
/* if we come here, exec has failed. bail. */
|
||||
_exit(255);
|
||||
default:
|
||||
/* Parent */
|
||||
_exit(0);
|
||||
}
|
||||
# else
|
||||
int pipefd[2]; /* pipe between parent and child */
|
||||
int pipe_error;
|
||||
char dummy;
|
||||
pid_t pid = -1;
|
||||
|
||||
/* Setup a pipe between the child and the parent, so that the parent
|
||||
* knows when the child has done the setsid() call and is allowed to
|
||||
@@ -227,30 +159,27 @@ http://developer.apple.com/documentation/Darwin/Reference/ManPages/man2/fork.2.h
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
# if defined(HAVE_SETSID) || defined(HAVE_SETPGID)
|
||||
# if defined(HAVE_SETSID) || defined(HAVE_SETPGID)
|
||||
/*
|
||||
* Change our process group. On some systems/shells a CTRL-C in the
|
||||
* shell where Vim was started would otherwise kill gvim!
|
||||
*/
|
||||
if (pid == 0) /* child */
|
||||
# if defined(HAVE_SETSID)
|
||||
# if defined(HAVE_SETSID)
|
||||
(void)setsid();
|
||||
# else
|
||||
# else
|
||||
(void)setpgid(0, 0);
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
if (!pipe_error)
|
||||
{
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
}
|
||||
|
||||
|
||||
# if defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION)
|
||||
# if defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION)
|
||||
/* Tell the session manager our new PID */
|
||||
gui_mch_forked();
|
||||
# endif
|
||||
|
||||
# endif
|
||||
}
|
||||
#else
|
||||
@@ -4820,6 +4749,8 @@ ex_gui(eap)
|
||||
* Check for "-f" argument: foreground, don't fork.
|
||||
* Also don't fork when started with "gvim -f".
|
||||
* Do fork when using "gui -b".
|
||||
* Note that Mac OS X will never fork on :gui since it can only fork on
|
||||
* startup right after scanning the command line.
|
||||
*/
|
||||
if (arg[0] == '-'
|
||||
&& (arg[1] == 'f' || arg[1] == 'b')
|
||||
@@ -4832,13 +4763,6 @@ ex_gui(eap)
|
||||
{
|
||||
/* Clear the command. Needed for when forking+exiting, to avoid part
|
||||
* of the argument ending up after the shell prompt. */
|
||||
|
||||
#ifdef MACOS_X
|
||||
/* os x doesn't really support fork(), so we can't fork of a gui
|
||||
* in an already running vim. see gui_start() for more details.
|
||||
*/
|
||||
gui.dofork = FALSE;
|
||||
#endif
|
||||
msg_clr_eos_force();
|
||||
gui_start();
|
||||
}
|
||||
|
||||
@@ -1291,6 +1291,23 @@ drawBalloon(beval)
|
||||
XtNy, ty,
|
||||
NULL);
|
||||
#endif
|
||||
/* Set tooltip colors */
|
||||
{
|
||||
Arg args[2];
|
||||
|
||||
#ifdef FEAT_GUI_MOTIF
|
||||
args[0].name = XmNbackground;
|
||||
args[0].value = gui.tooltip_bg_pixel;
|
||||
args[1].name = XmNforeground;
|
||||
args[1].value = gui.tooltip_fg_pixel;
|
||||
#else /* Athena */
|
||||
args[0].name = XtNbackground;
|
||||
args[0].value = gui.tooltip_bg_pixel;
|
||||
args[1].name = XtNforeground;
|
||||
args[1].value = gui.tooltip_fg_pixel;
|
||||
#endif
|
||||
XtSetValues(beval->balloonLabel, &args[0], XtNumber(args));
|
||||
}
|
||||
|
||||
XtPopup(beval->balloonShell, XtGrabNone);
|
||||
|
||||
|
||||
+31
-1
@@ -1582,6 +1582,17 @@ gui_mch_init(void)
|
||||
s_findrep_struct.lpstrReplaceWith[0] = NUL;
|
||||
s_findrep_struct.wFindWhatLen = MSWIN_FR_BUFSIZE;
|
||||
s_findrep_struct.wReplaceWithLen = MSWIN_FR_BUFSIZE;
|
||||
# if defined(FEAT_MBYTE) && defined(WIN3264)
|
||||
s_findrep_struct_w.lStructSize = sizeof(s_findrep_struct_w);
|
||||
s_findrep_struct_w.lpstrFindWhat =
|
||||
(LPWSTR)alloc(MSWIN_FR_BUFSIZE * sizeof(WCHAR));
|
||||
s_findrep_struct_w.lpstrFindWhat[0] = NUL;
|
||||
s_findrep_struct_w.lpstrReplaceWith =
|
||||
(LPWSTR)alloc(MSWIN_FR_BUFSIZE * sizeof(WCHAR));
|
||||
s_findrep_struct_w.lpstrReplaceWith[0] = NUL;
|
||||
s_findrep_struct_w.wFindWhatLen = MSWIN_FR_BUFSIZE;
|
||||
s_findrep_struct_w.wReplaceWithLen = MSWIN_FR_BUFSIZE;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
theend:
|
||||
@@ -2938,8 +2949,27 @@ dialog_callback(
|
||||
|
||||
/* If the edit box exists, copy the string. */
|
||||
if (s_textfield != NULL)
|
||||
GetDlgItemText(hwnd, DLG_NONBUTTON_CONTROL + 2,
|
||||
{
|
||||
# if defined(FEAT_MBYTE) && defined(WIN3264)
|
||||
/* If the OS is Windows NT, and 'encoding' differs from active
|
||||
* codepage: use wide function and convert text. */
|
||||
if (os_version.dwPlatformId == VER_PLATFORM_WIN32_NT
|
||||
&& enc_codepage >= 0 && (int)GetACP() != enc_codepage)
|
||||
{
|
||||
WCHAR *wp = (WCHAR *)alloc(IOSIZE * sizeof(WCHAR));
|
||||
char_u *p;
|
||||
|
||||
GetDlgItemTextW(hwnd, DLG_NONBUTTON_CONTROL + 2, wp, IOSIZE);
|
||||
p = utf16_to_enc(wp, NULL);
|
||||
vim_strncpy(s_textfield, p, IOSIZE);
|
||||
vim_free(p);
|
||||
vim_free(wp);
|
||||
}
|
||||
else
|
||||
# endif
|
||||
GetDlgItemText(hwnd, DLG_NONBUTTON_CONTROL + 2,
|
||||
s_textfield, IOSIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Need to check for IDOK because if the user just hits Return to
|
||||
|
||||
+88
-4
@@ -153,6 +153,9 @@ static int destroying = FALSE; /* call DestroyWindow() ourselves */
|
||||
#ifdef MSWIN_FIND_REPLACE
|
||||
static UINT s_findrep_msg = 0; /* set in gui_w[16/32].c */
|
||||
static FINDREPLACE s_findrep_struct;
|
||||
# if defined(FEAT_MBYTE) && defined(WIN3264)
|
||||
static FINDREPLACEW s_findrep_struct_w;
|
||||
# endif
|
||||
static HWND s_findrep_hwnd = NULL;
|
||||
static int s_findrep_is_find; /* TRUE for find dialog, FALSE
|
||||
for find/replace dialog */
|
||||
@@ -884,6 +887,45 @@ _OnMenu(
|
||||
#endif
|
||||
|
||||
#ifdef MSWIN_FIND_REPLACE
|
||||
# if defined(FEAT_MBYTE) && defined(WIN3264)
|
||||
/*
|
||||
* copy useful data from structure LPFINDREPLACE to structure LPFINDREPLACEW
|
||||
*/
|
||||
static void
|
||||
findrep_atow(LPFINDREPLACEW lpfrw, LPFINDREPLACE lpfr)
|
||||
{
|
||||
WCHAR *wp;
|
||||
|
||||
lpfrw->hwndOwner = lpfr->hwndOwner;
|
||||
lpfrw->Flags = lpfr->Flags;
|
||||
|
||||
wp = enc_to_utf16(lpfr->lpstrFindWhat, NULL);
|
||||
wcsncpy(lpfrw->lpstrFindWhat, wp, lpfrw->wFindWhatLen - 1);
|
||||
vim_free(wp);
|
||||
|
||||
/* the field "lpstrReplaceWith" doesn't need to be copied */
|
||||
}
|
||||
|
||||
/*
|
||||
* copy useful data from structure LPFINDREPLACEW to structure LPFINDREPLACE
|
||||
*/
|
||||
static void
|
||||
findrep_wtoa(LPFINDREPLACE lpfr, LPFINDREPLACEW lpfrw)
|
||||
{
|
||||
char_u *p;
|
||||
|
||||
lpfr->Flags = lpfrw->Flags;
|
||||
|
||||
p = utf16_to_enc(lpfrw->lpstrFindWhat, NULL);
|
||||
vim_strncpy(lpfr->lpstrFindWhat, p, lpfr->wFindWhatLen - 1);
|
||||
vim_free(p);
|
||||
|
||||
p = utf16_to_enc(lpfrw->lpstrReplaceWith, NULL);
|
||||
vim_strncpy(lpfr->lpstrReplaceWith, p, lpfr->wReplaceWithLen - 1);
|
||||
vim_free(p);
|
||||
}
|
||||
# endif
|
||||
|
||||
/*
|
||||
* Handle a Find/Replace window message.
|
||||
*/
|
||||
@@ -893,6 +935,16 @@ _OnFindRepl(void)
|
||||
int flags = 0;
|
||||
int down;
|
||||
|
||||
# if defined(FEAT_MBYTE) && defined(WIN3264)
|
||||
/* If the OS is Windows NT, and 'encoding' differs from active codepage:
|
||||
* convert text from wide string. */
|
||||
if (os_version.dwPlatformId == VER_PLATFORM_WIN32_NT
|
||||
&& enc_codepage >= 0 && (int)GetACP() != enc_codepage)
|
||||
{
|
||||
findrep_wtoa(&s_findrep_struct, &s_findrep_struct_w);
|
||||
}
|
||||
# endif
|
||||
|
||||
if (s_findrep_struct.Flags & FR_DIALOGTERM)
|
||||
/* Give main window the focus back. */
|
||||
(void)SetFocus(s_hwnd);
|
||||
@@ -1663,8 +1715,17 @@ process_message(void)
|
||||
if (msg.message == WM_OLE)
|
||||
{
|
||||
char_u *str = (char_u *)msg.lParam;
|
||||
add_to_input_buf(str, (int)STRLEN(str));
|
||||
vim_free(str);
|
||||
if (str == NULL || *str == NUL)
|
||||
{
|
||||
/* Message can't be ours, forward it. Fixes problem with Ultramon
|
||||
* 3.0.4 */
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
add_to_input_buf(str, (int)STRLEN(str));
|
||||
vim_free(str); /* was allocated in CVim::SendKeys() */
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -2553,7 +2614,19 @@ gui_mch_find_dialog(exarg_T *eap)
|
||||
if (!IsWindow(s_findrep_hwnd))
|
||||
{
|
||||
initialise_findrep(eap->arg);
|
||||
s_findrep_hwnd = FindText((LPFINDREPLACE) &s_findrep_struct);
|
||||
# if defined(FEAT_MBYTE) && defined(WIN3264)
|
||||
/* If the OS is Windows NT, and 'encoding' differs from active
|
||||
* codepage: convert text and use wide function. */
|
||||
if (os_version.dwPlatformId == VER_PLATFORM_WIN32_NT
|
||||
&& enc_codepage >= 0 && (int)GetACP() != enc_codepage)
|
||||
{
|
||||
findrep_atow(&s_findrep_struct_w, &s_findrep_struct);
|
||||
s_findrep_hwnd = FindTextW(
|
||||
(LPFINDREPLACEW) &s_findrep_struct_w);
|
||||
}
|
||||
else
|
||||
# endif
|
||||
s_findrep_hwnd = FindText((LPFINDREPLACE) &s_findrep_struct);
|
||||
}
|
||||
|
||||
set_window_title(s_findrep_hwnd,
|
||||
@@ -2578,7 +2651,18 @@ gui_mch_replace_dialog(exarg_T *eap)
|
||||
if (!IsWindow(s_findrep_hwnd))
|
||||
{
|
||||
initialise_findrep(eap->arg);
|
||||
s_findrep_hwnd = ReplaceText((LPFINDREPLACE) &s_findrep_struct);
|
||||
# if defined(FEAT_MBYTE) && defined(WIN3264)
|
||||
if (os_version.dwPlatformId == VER_PLATFORM_WIN32_NT
|
||||
&& enc_codepage >= 0 && (int)GetACP() != enc_codepage)
|
||||
{
|
||||
findrep_atow(&s_findrep_struct_w, &s_findrep_struct);
|
||||
s_findrep_hwnd = ReplaceTextW(
|
||||
(LPFINDREPLACEW) &s_findrep_struct_w);
|
||||
}
|
||||
else
|
||||
# endif
|
||||
s_findrep_hwnd = ReplaceText(
|
||||
(LPFINDREPLACE) &s_findrep_struct);
|
||||
}
|
||||
|
||||
set_window_title(s_findrep_hwnd,
|
||||
|
||||
+26
-33
@@ -1587,6 +1587,8 @@ gui_mch_uninit()
|
||||
XtCloseDisplay(gui.dpy);
|
||||
gui.dpy = NULL;
|
||||
vimShell = (Widget)0;
|
||||
vim_free(gui_argv);
|
||||
gui_argv = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1761,6 +1763,8 @@ gui_mch_exit(rc)
|
||||
* says that this isn't needed when exiting, so just skip it. */
|
||||
XtCloseDisplay(gui.dpy);
|
||||
#endif
|
||||
vim_free(gui_argv);
|
||||
gui_argv = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3439,47 +3443,37 @@ gui_mch_register_sign(signfile)
|
||||
char_u *signfile;
|
||||
{
|
||||
XpmAttributes attrs;
|
||||
XImage *sign;
|
||||
XImage *sign = NULL;
|
||||
int status;
|
||||
|
||||
/*
|
||||
* Setup the color substitution table.
|
||||
*/
|
||||
sign = NULL;
|
||||
if (signfile[0] != NUL && signfile[0] != '-')
|
||||
{
|
||||
sign = (XImage *)alloc(sizeof(XImage));
|
||||
if (sign != NULL)
|
||||
XpmColorSymbol color[5] =
|
||||
{
|
||||
XpmColorSymbol color[5] =
|
||||
{
|
||||
{"none", NULL, 0},
|
||||
{"iconColor1", NULL, 0},
|
||||
{"bottomShadowColor", NULL, 0},
|
||||
{"topShadowColor", NULL, 0},
|
||||
{"selectColor", NULL, 0}
|
||||
};
|
||||
attrs.valuemask = XpmColorSymbols;
|
||||
attrs.numsymbols = 2;
|
||||
attrs.colorsymbols = color;
|
||||
attrs.colorsymbols[0].pixel = gui.back_pixel;
|
||||
attrs.colorsymbols[1].pixel = gui.norm_pixel;
|
||||
status = XpmReadFileToImage(gui.dpy, (char *)signfile,
|
||||
{"none", NULL, 0},
|
||||
{"iconColor1", NULL, 0},
|
||||
{"bottomShadowColor", NULL, 0},
|
||||
{"topShadowColor", NULL, 0},
|
||||
{"selectColor", NULL, 0}
|
||||
};
|
||||
attrs.valuemask = XpmColorSymbols;
|
||||
attrs.numsymbols = 2;
|
||||
attrs.colorsymbols = color;
|
||||
attrs.colorsymbols[0].pixel = gui.back_pixel;
|
||||
attrs.colorsymbols[1].pixel = gui.norm_pixel;
|
||||
status = XpmReadFileToImage(gui.dpy, (char *)signfile,
|
||||
&sign, NULL, &attrs);
|
||||
|
||||
if (status == 0)
|
||||
{
|
||||
/* Sign width is fixed at two columns now.
|
||||
if (sign->width > gui.sign_width)
|
||||
gui.sign_width = sign->width + 8; */
|
||||
}
|
||||
else
|
||||
{
|
||||
vim_free(sign);
|
||||
sign = NULL;
|
||||
EMSG(_(e_signdata));
|
||||
}
|
||||
if (status == 0)
|
||||
{
|
||||
/* Sign width is fixed at two columns now.
|
||||
if (sign->width > gui.sign_width)
|
||||
gui.sign_width = sign->width + 8; */
|
||||
}
|
||||
else
|
||||
EMSG(_(e_signdata));
|
||||
}
|
||||
|
||||
return (void *)sign;
|
||||
@@ -3489,8 +3483,7 @@ gui_mch_register_sign(signfile)
|
||||
gui_mch_destroy_sign(sign)
|
||||
void *sign;
|
||||
{
|
||||
XFree(((XImage *)sign)->data);
|
||||
vim_free(sign);
|
||||
XDestroyImage((XImage*)sign);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+128
-7
@@ -93,12 +93,117 @@ cs_usage_msg(x)
|
||||
(void)EMSG2(_("E560: Usage: cs[cope] %s"), cs_cmds[(int)x].usage);
|
||||
}
|
||||
|
||||
#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
|
||||
|
||||
static enum
|
||||
{
|
||||
EXP_CSCOPE_SUBCMD, /* expand ":cscope" sub-commands */
|
||||
EXP_CSCOPE_FIND, /* expand ":cscope find" arguments */
|
||||
EXP_CSCOPE_KILL /* expand ":cscope kill" arguments */
|
||||
} expand_what;
|
||||
|
||||
/*
|
||||
* Function given to ExpandGeneric() to obtain the cscope command
|
||||
* expansion.
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
char_u *
|
||||
get_cscope_name(xp, idx)
|
||||
expand_T *xp;
|
||||
int idx;
|
||||
{
|
||||
switch (expand_what)
|
||||
{
|
||||
case EXP_CSCOPE_SUBCMD:
|
||||
/* Complete with sub-commands of ":cscope":
|
||||
* add, find, help, kill, reset, show */
|
||||
return (char_u *)cs_cmds[idx].name;
|
||||
case EXP_CSCOPE_FIND:
|
||||
{
|
||||
const char *query_type[] =
|
||||
{
|
||||
"c", "d", "e", "f", "g", "i", "s", "t", NULL
|
||||
};
|
||||
|
||||
/* Complete with query type of ":cscope find {query_type}".
|
||||
* {query_type} can be letters (c, d, ... t) or numbers (0, 1,
|
||||
* ..., 8) but only complete with letters, since numbers are
|
||||
* redundant. */
|
||||
return (char_u *)query_type[idx];
|
||||
}
|
||||
case EXP_CSCOPE_KILL:
|
||||
{
|
||||
int i;
|
||||
int current_idx = 0;
|
||||
static char_u connection[2];
|
||||
|
||||
/* ":cscope kill" accepts connection numbers or partial names of
|
||||
* the pathname of the cscope database as argument. Only complete
|
||||
* with connection numbers. -1 can also be used to kill all
|
||||
* connections. */
|
||||
for (i = 0; i < CSCOPE_MAX_CONNECTIONS; i++)
|
||||
{
|
||||
if (csinfo[i].fname == NULL)
|
||||
continue;
|
||||
if (current_idx++ == idx)
|
||||
{
|
||||
/* Connection number fits in one character since
|
||||
* CSCOPE_MAX_CONNECTIONS is < 10 */
|
||||
connection[0] = i + '0';
|
||||
connection[1] = NUL;
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
return (current_idx == idx && idx > 0) ? (char_u *)"-1" : NULL;
|
||||
}
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle command line completion for :cscope command.
|
||||
*/
|
||||
void
|
||||
set_context_in_cscope_cmd(xp, arg)
|
||||
expand_T *xp;
|
||||
char_u *arg;
|
||||
{
|
||||
char_u *p;
|
||||
|
||||
/* Default: expand subcommands */
|
||||
xp->xp_context = EXPAND_CSCOPE;
|
||||
expand_what = EXP_CSCOPE_SUBCMD;
|
||||
xp->xp_pattern = arg;
|
||||
|
||||
/* (part of) subcommand already typed */
|
||||
if (*arg != NUL)
|
||||
{
|
||||
p = skiptowhite(arg);
|
||||
if (*p != NUL) /* past first word */
|
||||
{
|
||||
xp->xp_pattern = skipwhite(p);
|
||||
if (*skiptowhite(xp->xp_pattern) != NUL)
|
||||
xp->xp_context = EXPAND_NOTHING;
|
||||
else if (STRNICMP(arg, "add", p - arg) == 0)
|
||||
xp->xp_context = EXPAND_FILES;
|
||||
else if (STRNICMP(arg, "kill", p - arg) == 0)
|
||||
expand_what = EXP_CSCOPE_KILL;
|
||||
else if (STRNICMP(arg, "find", p - arg) == 0)
|
||||
expand_what = EXP_CSCOPE_FIND;
|
||||
else
|
||||
xp->xp_context = EXPAND_NOTHING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* FEAT_CMDL_COMPL */
|
||||
|
||||
/*
|
||||
* PRIVATE: do_cscope_general
|
||||
*
|
||||
* find the command, print help if invalid, and the then call the
|
||||
* corresponding command function,
|
||||
* called from do_cscope and do_scscope
|
||||
* Find the command, print help if invalid, and then call the corresponding
|
||||
* command function.
|
||||
*/
|
||||
static void
|
||||
do_cscope_general(eap, make_split)
|
||||
@@ -659,6 +764,7 @@ cs_create_cmd(csoption, pattern)
|
||||
{
|
||||
char *cmd;
|
||||
short search;
|
||||
char *pat;
|
||||
|
||||
switch (csoption[0])
|
||||
{
|
||||
@@ -692,10 +798,17 @@ cs_create_cmd(csoption, pattern)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((cmd = (char *)alloc((unsigned)(strlen(pattern) + 2))) == NULL)
|
||||
/* Skip white space before the patter, except for text and pattern search,
|
||||
* they may want to use the leading white space. */
|
||||
pat = pattern;
|
||||
if (search != 4 && search != 6)
|
||||
while vim_iswhite(*pat)
|
||||
++pat;
|
||||
|
||||
if ((cmd = (char *)alloc((unsigned)(strlen(pat) + 2))) == NULL)
|
||||
return NULL;
|
||||
|
||||
(void)sprintf(cmd, "%d%s", search, pattern);
|
||||
(void)sprintf(cmd, "%d%s", search, pat);
|
||||
|
||||
return cmd;
|
||||
} /* cs_create_cmd */
|
||||
@@ -1177,8 +1290,16 @@ cs_help(eap)
|
||||
(void)MSG_PUTS(_("cscope commands:\n"));
|
||||
while (cmdp->name != NULL)
|
||||
{
|
||||
(void)smsg((char_u *)_("%-5s: %-30s (Usage: %s)"),
|
||||
cmdp->name, _(cmdp->help), cmdp->usage);
|
||||
char *help = _(cmdp->help);
|
||||
int space_cnt = 30 - vim_strsize((char_u *)help);
|
||||
|
||||
/* Use %*s rather than %30s to ensure proper alignment in utf-8 */
|
||||
if (space_cnt < 0)
|
||||
space_cnt = 0;
|
||||
(void)smsg((char_u *)_("%-5s: %s%*s (Usage: %s)"),
|
||||
cmdp->name,
|
||||
help, space_cnt, " ",
|
||||
cmdp->usage);
|
||||
if (strcmp(cmdp->name, "find") == 0)
|
||||
MSG_PUTS(_("\n"
|
||||
" c: Find functions calling this function\n"
|
||||
|
||||
+6
-2
@@ -353,9 +353,13 @@ CVim::SendKeys(BSTR keys)
|
||||
}
|
||||
|
||||
/* Pass the string to the main input loop. The memory will be freed when
|
||||
* the message is processed.
|
||||
* the message is processed. Except for an empty message, we don't need
|
||||
* to post it then.
|
||||
*/
|
||||
PostMessage(NULL, WM_OLE, 0, (LPARAM)str);
|
||||
if (*str == NUL)
|
||||
vim_free(str);
|
||||
else
|
||||
PostMessage(NULL, WM_OLE, 0, (LPARAM)str);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
+19
-10
@@ -1151,14 +1151,23 @@ VimToPython(typval_T *our_tv, int depth, PyObject *lookupDict)
|
||||
|
||||
/* Check if we run into a recursive loop. The item must be in lookupDict
|
||||
* then and we can use it again. */
|
||||
sprintf(ptrBuf, PRINTF_DECIMAL_LONG_U, (long_u)our_tv);
|
||||
result = PyDict_GetItemString(lookupDict, ptrBuf);
|
||||
if (result != NULL)
|
||||
Py_INCREF(result);
|
||||
else if (our_tv->v_type == VAR_STRING)
|
||||
if ((our_tv->v_type == VAR_LIST && our_tv->vval.v_list != NULL)
|
||||
|| (our_tv->v_type == VAR_DICT && our_tv->vval.v_dict != NULL))
|
||||
{
|
||||
sprintf(ptrBuf, PRINTF_DECIMAL_LONG_U,
|
||||
our_tv->v_type == VAR_LIST ? (long_u)our_tv->vval.v_list
|
||||
: (long_u)our_tv->vval.v_dict);
|
||||
result = PyDict_GetItemString(lookupDict, ptrBuf);
|
||||
if (result != NULL)
|
||||
{
|
||||
Py_INCREF(result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (our_tv->v_type == VAR_STRING)
|
||||
{
|
||||
result = Py_BuildValue("s", our_tv->vval.v_string);
|
||||
PyDict_SetItemString(lookupDict, ptrBuf, result);
|
||||
}
|
||||
else if (our_tv->v_type == VAR_NUMBER)
|
||||
{
|
||||
@@ -1167,7 +1176,6 @@ VimToPython(typval_T *our_tv, int depth, PyObject *lookupDict)
|
||||
/* For backwards compatibility numbers are stored as strings. */
|
||||
sprintf(buf, "%ld", (long)our_tv->vval.v_number);
|
||||
result = Py_BuildValue("s", buf);
|
||||
PyDict_SetItemString(lookupDict, ptrBuf, result);
|
||||
}
|
||||
# ifdef FEAT_FLOAT
|
||||
else if (our_tv->v_type == VAR_FLOAT)
|
||||
@@ -1176,7 +1184,6 @@ VimToPython(typval_T *our_tv, int depth, PyObject *lookupDict)
|
||||
|
||||
sprintf(buf, "%f", our_tv->vval.v_float);
|
||||
result = Py_BuildValue("s", buf);
|
||||
PyDict_SetItemString(lookupDict, ptrBuf, result);
|
||||
}
|
||||
# endif
|
||||
else if (our_tv->v_type == VAR_LIST)
|
||||
@@ -1185,10 +1192,11 @@ VimToPython(typval_T *our_tv, int depth, PyObject *lookupDict)
|
||||
listitem_T *curr;
|
||||
|
||||
result = PyList_New(0);
|
||||
PyDict_SetItemString(lookupDict, ptrBuf, result);
|
||||
|
||||
if (list != NULL)
|
||||
{
|
||||
PyDict_SetItemString(lookupDict, ptrBuf, result);
|
||||
|
||||
for (curr = list->lv_first; curr != NULL; curr = curr->li_next)
|
||||
{
|
||||
newObj = VimToPython(&curr->li_tv, depth + 1, lookupDict);
|
||||
@@ -1200,7 +1208,6 @@ VimToPython(typval_T *our_tv, int depth, PyObject *lookupDict)
|
||||
else if (our_tv->v_type == VAR_DICT)
|
||||
{
|
||||
result = PyDict_New();
|
||||
PyDict_SetItemString(lookupDict, ptrBuf, result);
|
||||
|
||||
if (our_tv->vval.v_dict != NULL)
|
||||
{
|
||||
@@ -1209,6 +1216,8 @@ VimToPython(typval_T *our_tv, int depth, PyObject *lookupDict)
|
||||
hashitem_T *hi;
|
||||
dictitem_T *di;
|
||||
|
||||
PyDict_SetItemString(lookupDict, ptrBuf, result);
|
||||
|
||||
for (hi = ht->ht_array; todo > 0; ++hi)
|
||||
{
|
||||
if (!HASHITEM_EMPTY(hi))
|
||||
|
||||
+21
-5
@@ -127,15 +127,31 @@
|
||||
#ifdef FEAT_LANGMAP
|
||||
/*
|
||||
* Adjust chars in a language according to 'langmap' option.
|
||||
* NOTE that there is NO overhead if 'langmap' is not set; but even
|
||||
* when set we only have to do 2 ifs and an array lookup.
|
||||
* NOTE that there is no noticeable overhead if 'langmap' is not set.
|
||||
* When set the overhead for characters < 256 is small.
|
||||
* Don't apply 'langmap' if the character comes from the Stuff buffer.
|
||||
* The do-while is just to ignore a ';' after the macro.
|
||||
*/
|
||||
# define LANGMAP_ADJUST(c, condition) do { \
|
||||
if (*p_langmap && (condition) && !KeyStuffed && (c) >= 0 && (c) < 256) \
|
||||
c = langmap_mapchar[c]; \
|
||||
# ifdef FEAT_MBYTE
|
||||
# define LANGMAP_ADJUST(c, condition) \
|
||||
do { \
|
||||
if (*p_langmap && (condition) && !KeyStuffed && (c) >= 0) \
|
||||
{ \
|
||||
if ((c) < 256) \
|
||||
c = langmap_mapchar[c]; \
|
||||
else \
|
||||
c = langmap_adjust_mb(c); \
|
||||
} \
|
||||
} while (0)
|
||||
# else
|
||||
# define LANGMAP_ADJUST(c, condition) \
|
||||
do { \
|
||||
if (*p_langmap && (condition) && !KeyStuffed && (c) >= 0 && (c) < 256) \
|
||||
c = langmap_mapchar[c]; \
|
||||
} while (0)
|
||||
# endif
|
||||
#else
|
||||
# define LANGMAP_ADJUST(c, condition) /* nop */
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
+14
-15
@@ -360,6 +360,11 @@ main
|
||||
command_line_scan(¶ms);
|
||||
TIME_MSG("parsing arguments");
|
||||
|
||||
#ifdef MACOS_X
|
||||
if (gui.starting && gui.dofork)
|
||||
macosx_fork(); /* Never returns */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* On some systems, when we compile with the GUI, we always use it. On Mac
|
||||
* there is no terminal version, and on Windows we can't fork one off with
|
||||
@@ -1282,9 +1287,10 @@ getout_preserve_modified(exitval)
|
||||
#endif
|
||||
|
||||
|
||||
/* Prepare proper exit*/
|
||||
/* Exit properly */
|
||||
void
|
||||
prepare_getout()
|
||||
getout(exitval)
|
||||
int exitval;
|
||||
{
|
||||
#ifdef FEAT_AUTOCMD
|
||||
buf_T *buf;
|
||||
@@ -1294,6 +1300,12 @@ prepare_getout()
|
||||
|
||||
exiting = TRUE;
|
||||
|
||||
/* When running in Ex mode an error causes us to exit with a non-zero exit
|
||||
* code. POSIX requires this, although it's not 100% clear from the
|
||||
* standard. */
|
||||
if (exmode_active)
|
||||
exitval += ex_exitval;
|
||||
|
||||
/* Position the cursor on the last screen line, below all the text */
|
||||
#ifdef FEAT_GUI
|
||||
if (!gui.in_use)
|
||||
@@ -1410,20 +1422,7 @@ prepare_getout()
|
||||
if (garbage_collect_at_exit)
|
||||
garbage_collect();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Exit properly */
|
||||
void
|
||||
getout(exitval)
|
||||
int exitval;
|
||||
{
|
||||
/* When running in Ex mode an error causes us to exit with a non-zero exit
|
||||
* code. POSIX requires this, although it's not 100% clear from the
|
||||
* standard. */
|
||||
if (exmode_active)
|
||||
exitval += ex_exitval;
|
||||
|
||||
prepare_getout();
|
||||
mch_exit(exitval);
|
||||
}
|
||||
|
||||
|
||||
+17
-5
@@ -976,7 +976,7 @@ wait_return(redraw)
|
||||
}
|
||||
}
|
||||
else if (msg_scrolled > Rows - 2
|
||||
&& (c == 'j' || c == K_DOWN || c == 'd'))
|
||||
&& (c == 'j' || c == K_DOWN || c == 'd' || c == 'f'))
|
||||
c = K_IGNORE;
|
||||
}
|
||||
} while ((had_got_int && c == Ctrl_C)
|
||||
@@ -2504,7 +2504,6 @@ do_more_prompt(typed_char)
|
||||
break;
|
||||
|
||||
case 'u': /* Up half a page */
|
||||
case K_PAGEUP:
|
||||
scroll = -(Rows / 2);
|
||||
break;
|
||||
|
||||
@@ -2513,10 +2512,12 @@ do_more_prompt(typed_char)
|
||||
break;
|
||||
|
||||
case 'b': /* one page back */
|
||||
case K_PAGEUP:
|
||||
scroll = -(Rows - 1);
|
||||
break;
|
||||
|
||||
case ' ': /* one extra page */
|
||||
case 'f':
|
||||
case K_PAGEDOWN:
|
||||
case K_LEFTMOUSE:
|
||||
scroll = Rows - 1;
|
||||
@@ -2552,7 +2553,6 @@ do_more_prompt(typed_char)
|
||||
{
|
||||
/* Jump to the choices of the dialog. */
|
||||
retval = TRUE;
|
||||
lines_left = Rows - 1;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@@ -2560,6 +2560,9 @@ do_more_prompt(typed_char)
|
||||
got_int = TRUE;
|
||||
quit_more = TRUE;
|
||||
}
|
||||
/* When there is some more output (wrapping line) display that
|
||||
* without another prompt. */
|
||||
lines_left = Rows - 1;
|
||||
break;
|
||||
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
@@ -3309,7 +3312,10 @@ do_dialog(type, title, message, buttons, dfltbutton, textfield)
|
||||
{
|
||||
c = gui_mch_dialog(type, title, message, buttons, dfltbutton,
|
||||
textfield);
|
||||
msg_end_prompt();
|
||||
/* avoid a hit-enter prompt without clearing the cmdline */
|
||||
need_wait_return = FALSE;
|
||||
emsg_on_display = FALSE;
|
||||
cmdline_row = msg_row;
|
||||
|
||||
/* Flush output to avoid that further messages and redrawing is done
|
||||
* in the wrong order. */
|
||||
@@ -4556,7 +4562,13 @@ vim_snprintf(str, str_m, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
|
||||
remove_trailing_zeroes = TRUE;
|
||||
}
|
||||
|
||||
if (fmt_spec == 'f' && abs_f > 1.0e307)
|
||||
if (fmt_spec == 'f' &&
|
||||
#ifdef VAX
|
||||
abs_f > 1.0e38
|
||||
#else
|
||||
abs_f > 1.0e307
|
||||
#endif
|
||||
)
|
||||
{
|
||||
/* Avoid a buffer overflow */
|
||||
strcpy(tmp, "inf");
|
||||
|
||||
+6
-2
@@ -2955,6 +2955,8 @@ change_warning(col)
|
||||
int col; /* column for message; non-zero when in insert
|
||||
mode and 'showmode' is on */
|
||||
{
|
||||
static char *w_readonly = N_("W10: Warning: Changing a readonly file");
|
||||
|
||||
if (curbuf->b_did_warn == FALSE
|
||||
&& curbufIsChanged() == 0
|
||||
#ifdef FEAT_AUTOCMD
|
||||
@@ -2977,8 +2979,10 @@ change_warning(col)
|
||||
if (msg_row == Rows - 1)
|
||||
msg_col = col;
|
||||
msg_source(hl_attr(HLF_W));
|
||||
MSG_PUTS_ATTR(_("W10: Warning: Changing a readonly file"),
|
||||
hl_attr(HLF_W) | MSG_HIST);
|
||||
MSG_PUTS_ATTR(_(w_readonly), hl_attr(HLF_W) | MSG_HIST);
|
||||
#ifdef FEAT_EVAL
|
||||
set_vim_var_string(VV_WARNINGMSG, (char_u *)_(w_readonly), -1);
|
||||
#endif
|
||||
msg_clr_eos();
|
||||
(void)msg_end();
|
||||
if (msg_silent == 0 && !silent_mode)
|
||||
|
||||
+17
-3
@@ -496,7 +496,8 @@ check_cursor_col()
|
||||
{
|
||||
colnr_T len;
|
||||
#ifdef FEAT_VIRTUALEDIT
|
||||
colnr_T oldcol = curwin->w_cursor.col + curwin->w_cursor.coladd;
|
||||
colnr_T oldcol = curwin->w_cursor.col;
|
||||
colnr_T oldcoladd = curwin->w_cursor.col + curwin->w_cursor.coladd;
|
||||
#endif
|
||||
|
||||
len = (colnr_T)STRLEN(ml_get_curline());
|
||||
@@ -535,7 +536,13 @@ check_cursor_col()
|
||||
if (oldcol == MAXCOL)
|
||||
curwin->w_cursor.coladd = 0;
|
||||
else if (ve_flags == VE_ALL)
|
||||
curwin->w_cursor.coladd = oldcol - curwin->w_cursor.col;
|
||||
{
|
||||
if (oldcoladd > curwin->w_cursor.col)
|
||||
curwin->w_cursor.coladd = oldcoladd - curwin->w_cursor.col;
|
||||
else
|
||||
/* avoid weird number when there is a miscalculation or overflow */
|
||||
curwin->w_cursor.coladd = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1010,6 +1017,9 @@ free_all_mem()
|
||||
# if defined(FEAT_PROFILE)
|
||||
do_cmdline_cmd((char_u *)"profdel *");
|
||||
# endif
|
||||
# if defined(FEAT_KEYMAP)
|
||||
do_cmdline_cmd((char_u *)"set keymap=");
|
||||
#endif
|
||||
|
||||
# ifdef FEAT_TITLE
|
||||
free_titles();
|
||||
@@ -1034,6 +1044,9 @@ free_all_mem()
|
||||
free_regexp_stuff();
|
||||
free_tag_stuff();
|
||||
free_cd_dir();
|
||||
# ifdef FEAT_SIGNS
|
||||
free_signs();
|
||||
# endif
|
||||
# ifdef FEAT_EVAL
|
||||
set_expr_line(NULL);
|
||||
# endif
|
||||
@@ -4696,7 +4709,8 @@ vim_findfile(search_ctx_arg)
|
||||
stackp->ffs_filearray_cur = i + 1;
|
||||
ff_push(search_ctx, stackp);
|
||||
|
||||
simplify_filename(file_path);
|
||||
if (!path_with_url(file_path))
|
||||
simplify_filename(file_path);
|
||||
if (mch_dirname(ff_expand_buffer, MAXPATHL)
|
||||
== OK)
|
||||
{
|
||||
|
||||
@@ -33,7 +33,6 @@ FILE *nb_debug = NULL;
|
||||
u_int nb_dlevel = 0; /* nb_debug verbosity level */
|
||||
|
||||
void nbdb(char *, ...);
|
||||
void nbtrace(char *, ...);
|
||||
|
||||
static int lookup(char *);
|
||||
#ifdef USE_NB_ERRORHANDLER
|
||||
@@ -100,25 +99,6 @@ nbdebug_log_init(
|
||||
} /* end nbdebug_log_init */
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
nbtrace(
|
||||
char *fmt,
|
||||
...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (nb_debug!= NULL && (nb_dlevel & (NB_TRACE | NB_TRACE_VERBOSE))) {
|
||||
va_start(ap, fmt);
|
||||
vfprintf(nb_debug, fmt, ap);
|
||||
va_end(ap);
|
||||
fflush(nb_debug);
|
||||
}
|
||||
|
||||
} /* end nbtrace */
|
||||
|
||||
|
||||
void
|
||||
nbdbg(
|
||||
char *fmt,
|
||||
@@ -136,23 +116,6 @@ nbdbg(
|
||||
} /* end nbdbg */
|
||||
|
||||
|
||||
void
|
||||
nbprt(
|
||||
char *fmt,
|
||||
...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (nb_debug != NULL && nb_dlevel & NB_PRINT) {
|
||||
va_start(ap, fmt);
|
||||
vfprintf(nb_debug, fmt, ap);
|
||||
va_end(ap);
|
||||
fflush(nb_debug);
|
||||
}
|
||||
|
||||
} /* end nbprt */
|
||||
|
||||
|
||||
static int
|
||||
lookup(
|
||||
char *file)
|
||||
|
||||
@@ -43,8 +43,6 @@ typedef enum {
|
||||
|
||||
|
||||
void nbdbg(char *, ...);
|
||||
void nbprt(char *, ...);
|
||||
void nbtrace(char *, ...);
|
||||
|
||||
void nbdebug_wait __ARGS((u_int wait_flags, char *wait_var, u_int wait_secs));
|
||||
void nbdebug_log_init __ARGS((char *log_var, char *level_var));
|
||||
@@ -70,19 +68,5 @@ nbdbg(
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nbprt(
|
||||
char *fmt,
|
||||
...)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nbtrace(
|
||||
char *fmt,
|
||||
...)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* NBDEBUG */
|
||||
#endif /* NBDEBUG_H */
|
||||
|
||||
+9
-27
@@ -1924,7 +1924,7 @@ nb_do_cmd(
|
||||
vim_free(path);
|
||||
if (bufp == NULL)
|
||||
{
|
||||
nbdebug((" File %s not found in setBufferNumber\n", args));
|
||||
nbdebug((" File %s not found in setBufferNumber\n", args));
|
||||
EMSG2("E642: File %s not found in setBufferNumber", args);
|
||||
return FAIL;
|
||||
}
|
||||
@@ -2318,7 +2318,7 @@ nb_do_cmd(
|
||||
}
|
||||
if (pos)
|
||||
{
|
||||
coloncmd(":sign place %d line=%d name=%d buffer=%d",
|
||||
coloncmd(":sign place %d line=%ld name=%d buffer=%d",
|
||||
serNum, pos->lnum, typeNum, buf->bufp->b_fnum);
|
||||
if (typeNum == curPCtype)
|
||||
coloncmd(":sign jump %d buffer=%d", serNum,
|
||||
@@ -2422,7 +2422,7 @@ nb_do_cmd(
|
||||
GUARDED) == 0)
|
||||
{
|
||||
coloncmd(
|
||||
":sign place %d line=%d name=%d buffer=%d",
|
||||
":sign place %d line=%ld name=%d buffer=%d",
|
||||
guardId++, lnum, GUARDED,
|
||||
buf->bufp->b_fnum);
|
||||
}
|
||||
@@ -2921,44 +2921,26 @@ netbeans_file_opened(buf_T *bufp)
|
||||
}
|
||||
|
||||
/*
|
||||
* Tell netbeans a file was closed.
|
||||
* Tell netbeans that a file was deleted or wiped out.
|
||||
*/
|
||||
void
|
||||
netbeans_file_closed(buf_T *bufp)
|
||||
netbeans_file_killed(buf_T *bufp)
|
||||
{
|
||||
int bufno = nb_getbufno(bufp);
|
||||
nbbuf_T *nbbuf = nb_get_buf(bufno);
|
||||
char buffer[2*MAXPATHL];
|
||||
|
||||
if (!haveConnection || bufno < 0)
|
||||
if (!haveConnection || bufno == -1)
|
||||
return;
|
||||
|
||||
if (!netbeansCloseFile)
|
||||
{
|
||||
nbdebug(("Ignoring file_closed for %s. File was closed from IDE\n",
|
||||
bufp->b_ffname));
|
||||
return;
|
||||
}
|
||||
|
||||
nbdebug(("netbeans_file_closed:\n"));
|
||||
nbdebug((" Closing bufno: %d", bufno));
|
||||
if (curbuf != NULL && curbuf != bufp)
|
||||
{
|
||||
nbdebug((" Curbuf bufno: %d\n", nb_getbufno(curbuf)));
|
||||
}
|
||||
else if (curbuf == bufp)
|
||||
{
|
||||
nbdebug((" curbuf == bufp\n"));
|
||||
}
|
||||
|
||||
if (bufno <= 0)
|
||||
return;
|
||||
nbdebug(("netbeans_file_killed:\n"));
|
||||
nbdebug((" Killing bufno: %d", bufno));
|
||||
|
||||
sprintf(buffer, "%d:killed=%d\n", bufno, r_cmdno);
|
||||
|
||||
nbdebug(("EVT: %s", buffer));
|
||||
|
||||
nb_send(buffer, "netbeans_file_closed");
|
||||
nb_send(buffer, "netbeans_file_killed");
|
||||
|
||||
if (nbbuf != NULL)
|
||||
nbbuf->bufp = NULL;
|
||||
|
||||
+3
-16
@@ -651,10 +651,7 @@ normal_cmd(oap, toplevel)
|
||||
* Get the command character from the user.
|
||||
*/
|
||||
c = safe_vgetc();
|
||||
|
||||
#ifdef FEAT_LANGMAP
|
||||
LANGMAP_ADJUST(c, TRUE);
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_VISUAL
|
||||
/*
|
||||
@@ -744,9 +741,7 @@ getcount:
|
||||
}
|
||||
++no_zero_mapping; /* don't map zero here */
|
||||
c = plain_vgetc();
|
||||
#ifdef FEAT_LANGMAP
|
||||
LANGMAP_ADJUST(c, TRUE);
|
||||
#endif
|
||||
--no_zero_mapping;
|
||||
if (ctrl_w)
|
||||
{
|
||||
@@ -769,9 +764,7 @@ getcount:
|
||||
++no_mapping;
|
||||
++allow_keys; /* no mapping for nchar, but keys */
|
||||
c = plain_vgetc(); /* get next character */
|
||||
#ifdef FEAT_LANGMAP
|
||||
LANGMAP_ADJUST(c, TRUE);
|
||||
#endif
|
||||
--no_mapping;
|
||||
--allow_keys;
|
||||
#ifdef FEAT_CMDL_INFO
|
||||
@@ -959,9 +952,7 @@ getcount:
|
||||
* "gr", "g'" and "g`".
|
||||
*/
|
||||
ca.nchar = plain_vgetc();
|
||||
#ifdef FEAT_LANGMAP
|
||||
LANGMAP_ADJUST(ca.nchar, TRUE);
|
||||
#endif
|
||||
#ifdef FEAT_CMDL_INFO
|
||||
need_flushbuf |= add_to_showcmd(ca.nchar);
|
||||
#endif
|
||||
@@ -1062,10 +1053,8 @@ getcount:
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_LANGMAP
|
||||
/* adjust chars > 127, except after "tTfFr" commands */
|
||||
LANGMAP_ADJUST(*cp, !lang);
|
||||
#endif
|
||||
#ifdef FEAT_RIGHTLEFT
|
||||
/* adjust Hebrew mapped char */
|
||||
if (p_hkmap && lang && KeyTyped)
|
||||
@@ -4649,9 +4638,7 @@ nv_zet(cap)
|
||||
++no_mapping;
|
||||
++allow_keys; /* no mapping for nchar, but allow key codes */
|
||||
nchar = plain_vgetc();
|
||||
#ifdef FEAT_LANGMAP
|
||||
LANGMAP_ADJUST(nchar, TRUE);
|
||||
#endif
|
||||
--no_mapping;
|
||||
--allow_keys;
|
||||
#ifdef FEAT_CMDL_INFO
|
||||
@@ -5007,9 +4994,7 @@ dozet:
|
||||
++no_mapping;
|
||||
++allow_keys; /* no mapping for nchar, but allow key codes */
|
||||
nchar = plain_vgetc();
|
||||
#ifdef FEAT_LANGMAP
|
||||
LANGMAP_ADJUST(nchar, TRUE);
|
||||
#endif
|
||||
--no_mapping;
|
||||
--allow_keys;
|
||||
#ifdef FEAT_CMDL_INFO
|
||||
@@ -6811,6 +6796,8 @@ nv_replace(cap)
|
||||
/* Visual mode "r" */
|
||||
if (VIsual_active)
|
||||
{
|
||||
if (got_int)
|
||||
reset_VIsual();
|
||||
nv_operator(cap);
|
||||
return;
|
||||
}
|
||||
@@ -7867,7 +7854,7 @@ nv_g_cmd(cap)
|
||||
else
|
||||
i = curwin->w_leftcol;
|
||||
/* Go to the middle of the screen line. When 'number' is on and lines
|
||||
* are wrapping the middle can be more to the left.*/
|
||||
* are wrapping the middle can be more to the left. */
|
||||
if (cap->nchar == 'm')
|
||||
i += (W_WIDTH(curwin) - curwin_col_off()
|
||||
+ ((curwin->w_p_wrap && i > 0)
|
||||
|
||||
@@ -72,11 +72,11 @@ static struct yankreg *y_previous = NULL; /* ptr to last written yankreg */
|
||||
*/
|
||||
struct block_def
|
||||
{
|
||||
int startspaces; /* 'extra' cols of first char */
|
||||
int endspaces; /* 'extra' cols of first char */
|
||||
int startspaces; /* 'extra' cols before first char */
|
||||
int endspaces; /* 'extra' cols after last char */
|
||||
int textlen; /* chars in block */
|
||||
char_u *textstart; /* pointer to 1st char in block */
|
||||
colnr_T textcol; /* cols of chars (at least part.) in block */
|
||||
char_u *textstart; /* pointer to 1st char (partially) in block */
|
||||
colnr_T textcol; /* index of chars (partially) in block */
|
||||
colnr_T start_vcol; /* start col of 1st char wholly inside block */
|
||||
colnr_T end_vcol; /* start col of 1st char wholly after block */
|
||||
#ifdef FEAT_VISUALEXTRA
|
||||
@@ -382,15 +382,14 @@ shift_block(oap, amount)
|
||||
{
|
||||
int left = (oap->op_type == OP_LSHIFT);
|
||||
int oldstate = State;
|
||||
int total, split;
|
||||
char_u *newp, *oldp, *midp, *ptr;
|
||||
int total;
|
||||
char_u *newp, *oldp;
|
||||
int oldcol = curwin->w_cursor.col;
|
||||
int p_sw = (int)curbuf->b_p_sw;
|
||||
int p_ts = (int)curbuf->b_p_ts;
|
||||
struct block_def bd;
|
||||
int internal = 0;
|
||||
int incr;
|
||||
colnr_T vcol, col = 0, ws_vcol;
|
||||
colnr_T ws_vcol;
|
||||
int i = 0, j = 0;
|
||||
int len;
|
||||
|
||||
@@ -456,67 +455,89 @@ shift_block(oap, amount)
|
||||
}
|
||||
else /* left */
|
||||
{
|
||||
vcol = oap->start_vcol;
|
||||
/* walk vcol past ws to be removed */
|
||||
for (midp = oldp + bd.textcol;
|
||||
vcol < (oap->start_vcol + total) && vim_iswhite(*midp); )
|
||||
{
|
||||
incr = lbr_chartabsize_adv(&midp, (colnr_T)vcol);
|
||||
vcol += incr;
|
||||
}
|
||||
/* internal is the block-internal ws replacing a split TAB */
|
||||
if (vcol > (oap->start_vcol + total))
|
||||
{
|
||||
/* we have to split the TAB *(midp-1) */
|
||||
internal = vcol - (oap->start_vcol + total);
|
||||
}
|
||||
/* if 'expandtab' is not set, use TABs */
|
||||
colnr_T destination_col; /* column to which text in block will
|
||||
be shifted */
|
||||
char_u *verbatim_copy_end; /* end of the part of the line which is
|
||||
copied verbatim */
|
||||
colnr_T verbatim_copy_width;/* the (displayed) width of this part
|
||||
of line */
|
||||
unsigned fill; /* nr of spaces that replace a TAB */
|
||||
unsigned new_line_len; /* the length of the line after the
|
||||
block shift */
|
||||
size_t block_space_width;
|
||||
size_t shift_amount;
|
||||
char_u *non_white = bd.textstart;
|
||||
colnr_T non_white_col;
|
||||
|
||||
split = bd.startspaces + internal;
|
||||
if (split > 0)
|
||||
{
|
||||
if (!curbuf->b_p_et)
|
||||
{
|
||||
for (ptr = oldp, col = 0; ptr < oldp+bd.textcol; )
|
||||
col += lbr_chartabsize_adv(&ptr, (colnr_T)col);
|
||||
/*
|
||||
* Firstly, let's find the first non-whitespace character that is
|
||||
* displayed after the block's start column and the character's column
|
||||
* number. Also, let's calculate the width of all the whitespace
|
||||
* characters that are displayed in the block and precede the searched
|
||||
* non-whitespace character.
|
||||
*/
|
||||
|
||||
/* col+1 now equals the start col of the first char of the
|
||||
* block (may be < oap.start_vcol if we're splitting a TAB) */
|
||||
i = ((col % p_ts) + split) / p_ts; /* number of tabs */
|
||||
}
|
||||
if (i)
|
||||
j = ((col % p_ts) + split) % p_ts; /* number of spp */
|
||||
else
|
||||
j = split;
|
||||
/* If "bd.startspaces" is set, "bd.textstart" points to the character,
|
||||
* the part of which is displayed at the block's beginning. Let's start
|
||||
* searching from the next character. */
|
||||
if (bd.startspaces)
|
||||
mb_ptr_adv(non_white);
|
||||
|
||||
/* The character's column is in "bd.start_vcol". */
|
||||
non_white_col = bd.start_vcol;
|
||||
|
||||
while (vim_iswhite(*non_white))
|
||||
{
|
||||
incr = lbr_chartabsize_adv(&non_white, non_white_col);
|
||||
non_white_col += incr;
|
||||
}
|
||||
|
||||
newp = alloc_check(bd.textcol + i + j + (unsigned)STRLEN(midp) + 1);
|
||||
block_space_width = non_white_col - oap->start_vcol;
|
||||
/* We will shift by "total" or "block_space_width", whichever is less.
|
||||
*/
|
||||
shift_amount = (block_space_width < total? block_space_width: total);
|
||||
|
||||
/* The column to which we will shift the text. */
|
||||
destination_col = non_white_col - shift_amount;
|
||||
|
||||
/* Now let's find out how much of the beginning of the line we can
|
||||
* reuse without modification. */
|
||||
verbatim_copy_end = bd.textstart;
|
||||
verbatim_copy_width = bd.start_vcol;
|
||||
|
||||
/* If "bd.startspaces" is set, "bd.textstart" points to the character
|
||||
* preceding the block. We have to subtract its width to obtain its
|
||||
* column number. */
|
||||
if (bd.startspaces)
|
||||
verbatim_copy_width -= bd.start_char_vcols;
|
||||
while (verbatim_copy_width < destination_col)
|
||||
{
|
||||
incr = lbr_chartabsize(verbatim_copy_end, verbatim_copy_width);
|
||||
if (verbatim_copy_width + incr > destination_col)
|
||||
break;
|
||||
verbatim_copy_width += incr;
|
||||
mb_ptr_adv(verbatim_copy_end);
|
||||
}
|
||||
|
||||
/* If "destination_col" is different from the width of the initial
|
||||
* part of the line that will be copied, it means we encountered a tab
|
||||
* character, which we will have to partly replace with spaces. */
|
||||
fill = destination_col - verbatim_copy_width;
|
||||
|
||||
/* The replacement line will consist of:
|
||||
* - the beginning of the original line up to "verbatim_copy_end",
|
||||
* - "fill" number of spaces,
|
||||
* - the rest of the line, pointed to by non_white. */
|
||||
new_line_len = (unsigned)(verbatim_copy_end - oldp)
|
||||
+ fill
|
||||
+ (unsigned)STRLEN(non_white) + 1;
|
||||
|
||||
newp = alloc_check(new_line_len);
|
||||
if (newp == NULL)
|
||||
return;
|
||||
vim_memset(newp, NUL, (size_t)(bd.textcol + i + j + STRLEN(midp) + 1));
|
||||
|
||||
/* copy first part we want to keep */
|
||||
mch_memmove(newp, oldp, (size_t)bd.textcol);
|
||||
/* Now copy any TABS and spp to ensure correct alignment! */
|
||||
while (vim_iswhite(*midp))
|
||||
{
|
||||
if (*midp == TAB)
|
||||
i++;
|
||||
else /*space */
|
||||
j++;
|
||||
midp++;
|
||||
}
|
||||
/* We might have an extra TAB worth of spp now! */
|
||||
if (j / p_ts && !curbuf->b_p_et)
|
||||
{
|
||||
i++;
|
||||
j -= p_ts;
|
||||
}
|
||||
copy_chars(newp + bd.textcol, (size_t)i, TAB);
|
||||
copy_spaces(newp + bd.textcol + i, (size_t)j);
|
||||
|
||||
/* the end */
|
||||
STRMOVE(newp + STRLEN(newp), midp);
|
||||
mch_memmove(newp, oldp, (size_t)(verbatim_copy_end - oldp));
|
||||
copy_spaces(newp + (verbatim_copy_end - oldp), (size_t)fill);
|
||||
STRMOVE(newp + (verbatim_copy_end - oldp) + fill, non_white);
|
||||
}
|
||||
/* replace the line */
|
||||
ml_replace(curwin->w_cursor.lnum, newp, FALSE);
|
||||
@@ -4851,7 +4872,8 @@ paragraph_start(lnum)
|
||||
* - textlen includes the first/last char to be (partly) deleted
|
||||
* - start/endspaces is the number of columns that are taken by the
|
||||
* first/last deleted char minus the number of columns that have to be
|
||||
* deleted. for yank and tilde:
|
||||
* deleted.
|
||||
* for yank and tilde:
|
||||
* - textlen includes the first/last char to be wholly yanked
|
||||
* - start/endspaces is the number of columns of the first/last yanked char
|
||||
* that are to be yanked.
|
||||
|
||||
+220
-45
@@ -4178,11 +4178,23 @@ do_set(arg, opt_flags)
|
||||
&& options[opt_idx].var == VAR_WIN)
|
||||
goto skip;
|
||||
|
||||
/* Disallow changing some options from modelines */
|
||||
if ((opt_flags & OPT_MODELINE) && (flags & P_SECURE))
|
||||
/* Disallow changing some options from modelines. */
|
||||
if (opt_flags & OPT_MODELINE)
|
||||
{
|
||||
errmsg = (char_u *)_("E520: Not allowed in a modeline");
|
||||
goto skip;
|
||||
if (flags & P_SECURE)
|
||||
{
|
||||
errmsg = (char_u *)_("E520: Not allowed in a modeline");
|
||||
goto skip;
|
||||
}
|
||||
#ifdef FEAT_DIFF
|
||||
/* In diff mode some options are overruled. This avoids that
|
||||
* 'foldmethod' becomes "marker" instead of "diff" and that
|
||||
* "wrap" gets set. */
|
||||
if (curwin->w_p_diff
|
||||
&& (options[opt_idx].indir == PV_FDM
|
||||
|| options[opt_idx].indir == PV_WRAP))
|
||||
goto skip;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_SANDBOX
|
||||
@@ -5332,6 +5344,21 @@ insecure_flag(opt_idx, opt_flags)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_TITLE
|
||||
static void redraw_titles __ARGS((void));
|
||||
|
||||
/*
|
||||
* Redraw the window title and/or tab page text later.
|
||||
*/
|
||||
static void redraw_titles()
|
||||
{
|
||||
need_maketitle = TRUE;
|
||||
# ifdef FEAT_WINDOWS
|
||||
redraw_tabline = TRUE;
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set a string option to a new value (without checking the effect).
|
||||
* The string is copied into allocated memory.
|
||||
@@ -5471,6 +5498,10 @@ did_set_string_option(opt_idx, varp, new_value_alloced, oldval, errbuf,
|
||||
int did_chartab = FALSE;
|
||||
char_u **gvarp;
|
||||
long_u free_oldval = (options[opt_idx].flags & P_ALLOCED);
|
||||
#ifdef FEAT_GUI
|
||||
/* set when changing an option that only requires a redraw in the GUI */
|
||||
int redraw_gui_only = FALSE;
|
||||
#endif
|
||||
|
||||
/* Get the global option to compare with, otherwise we would have to check
|
||||
* two values for all local options. */
|
||||
@@ -5732,7 +5763,7 @@ did_set_string_option(opt_idx, varp, new_value_alloced, oldval, errbuf,
|
||||
{
|
||||
# ifdef FEAT_TITLE
|
||||
/* May show a "+" in the title now. */
|
||||
need_maketitle = TRUE;
|
||||
redraw_titles();
|
||||
# endif
|
||||
/* Add 'fileencoding' to the swap file. */
|
||||
ml_setflags(curbuf);
|
||||
@@ -5751,7 +5782,7 @@ did_set_string_option(opt_idx, varp, new_value_alloced, oldval, errbuf,
|
||||
{
|
||||
errmsg = mb_init();
|
||||
# ifdef FEAT_TITLE
|
||||
need_maketitle = TRUE;
|
||||
redraw_titles();
|
||||
# endif
|
||||
}
|
||||
}
|
||||
@@ -5834,14 +5865,28 @@ did_set_string_option(opt_idx, varp, new_value_alloced, oldval, errbuf,
|
||||
/* load or unload key mapping tables */
|
||||
errmsg = keymap_init();
|
||||
|
||||
/* When successfully installed a new keymap switch on using it. */
|
||||
if (*curbuf->b_p_keymap != NUL && errmsg == NULL)
|
||||
if (errmsg == NULL)
|
||||
{
|
||||
curbuf->b_p_iminsert = B_IMODE_LMAP;
|
||||
if (curbuf->b_p_imsearch != B_IMODE_USE_INSERT)
|
||||
curbuf->b_p_imsearch = B_IMODE_LMAP;
|
||||
set_iminsert_global();
|
||||
set_imsearch_global();
|
||||
if (*curbuf->b_p_keymap != NUL)
|
||||
{
|
||||
/* Installed a new keymap, switch on using it. */
|
||||
curbuf->b_p_iminsert = B_IMODE_LMAP;
|
||||
if (curbuf->b_p_imsearch != B_IMODE_USE_INSERT)
|
||||
curbuf->b_p_imsearch = B_IMODE_LMAP;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Cleared the keymap, may reset 'iminsert' and 'imsearch'. */
|
||||
if (curbuf->b_p_iminsert == B_IMODE_LMAP)
|
||||
curbuf->b_p_iminsert = B_IMODE_NONE;
|
||||
if (curbuf->b_p_imsearch == B_IMODE_LMAP)
|
||||
curbuf->b_p_imsearch = B_IMODE_USE_INSERT;
|
||||
}
|
||||
if ((opt_flags & OPT_LOCAL) == 0)
|
||||
{
|
||||
set_iminsert_global();
|
||||
set_imsearch_global();
|
||||
}
|
||||
# ifdef FEAT_WINDOWS
|
||||
status_redraw_curbuf();
|
||||
# endif
|
||||
@@ -5864,7 +5909,7 @@ did_set_string_option(opt_idx, varp, new_value_alloced, oldval, errbuf,
|
||||
else
|
||||
curbuf->b_p_tx = FALSE;
|
||||
#ifdef FEAT_TITLE
|
||||
need_maketitle = TRUE;
|
||||
redraw_titles();
|
||||
#endif
|
||||
/* update flag in swap file */
|
||||
ml_setflags(curbuf);
|
||||
@@ -6045,15 +6090,23 @@ did_set_string_option(opt_idx, varp, new_value_alloced, oldval, errbuf,
|
||||
/* ":set t_Co=0" and ":set t_Co=1" do ":set t_Co=" */
|
||||
if (varp == &T_CCO)
|
||||
{
|
||||
t_colors = atoi((char *)T_CCO);
|
||||
if (t_colors <= 1)
|
||||
int colors = atoi((char *)T_CCO);
|
||||
|
||||
/* Only reinitialize colors if t_Co value has really changed to
|
||||
* avoid expensive reload of colorscheme if t_Co is set to the
|
||||
* same value multiple times. */
|
||||
if (colors != t_colors)
|
||||
{
|
||||
if (new_value_alloced)
|
||||
vim_free(T_CCO);
|
||||
T_CCO = empty_option;
|
||||
t_colors = colors;
|
||||
if (t_colors <= 1)
|
||||
{
|
||||
if (new_value_alloced)
|
||||
vim_free(T_CCO);
|
||||
T_CCO = empty_option;
|
||||
}
|
||||
/* We now have a different color setup, initialize it again. */
|
||||
init_highlight(TRUE, FALSE);
|
||||
}
|
||||
/* We now have a different color setup, initialize it again. */
|
||||
init_highlight(TRUE, FALSE);
|
||||
}
|
||||
ttest(FALSE);
|
||||
if (varp == &T_ME)
|
||||
@@ -6124,6 +6177,7 @@ did_set_string_option(opt_idx, varp, new_value_alloced, oldval, errbuf,
|
||||
errmsg = (char_u *)N_("E596: Invalid font(s)");
|
||||
}
|
||||
}
|
||||
redraw_gui_only = TRUE;
|
||||
}
|
||||
# ifdef FEAT_XFONTSET
|
||||
else if (varp == &p_guifontset)
|
||||
@@ -6132,6 +6186,7 @@ did_set_string_option(opt_idx, varp, new_value_alloced, oldval, errbuf,
|
||||
errmsg = (char_u *)N_("E597: can't select fontset");
|
||||
else if (gui.in_use && gui_init_font(p_guifontset, TRUE) != OK)
|
||||
errmsg = (char_u *)N_("E598: Invalid fontset");
|
||||
redraw_gui_only = TRUE;
|
||||
}
|
||||
# endif
|
||||
# ifdef FEAT_MBYTE
|
||||
@@ -6141,6 +6196,7 @@ did_set_string_option(opt_idx, varp, new_value_alloced, oldval, errbuf,
|
||||
errmsg = (char_u *)N_("E533: can't select wide font");
|
||||
else if (gui_get_wide_font() == FAIL)
|
||||
errmsg = (char_u *)N_("E534: Invalid wide font");
|
||||
redraw_gui_only = TRUE;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
@@ -6202,13 +6258,24 @@ did_set_string_option(opt_idx, varp, new_value_alloced, oldval, errbuf,
|
||||
#ifdef FEAT_GUI
|
||||
/* 'guioptions' */
|
||||
else if (varp == &p_go)
|
||||
{
|
||||
gui_init_which_components(oldval);
|
||||
redraw_gui_only = TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(FEAT_GUI_TABLINE)
|
||||
/* 'guitablabel' */
|
||||
else if (varp == &p_gtl)
|
||||
{
|
||||
redraw_tabline = TRUE;
|
||||
redraw_gui_only = TRUE;
|
||||
}
|
||||
/* 'guitabtooltip' */
|
||||
else if (varp == &p_gtt)
|
||||
{
|
||||
redraw_gui_only = TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(FEAT_MOUSE_TTY) && (defined(UNIX) || defined(VMS))
|
||||
@@ -6797,7 +6864,11 @@ did_set_string_option(opt_idx, varp, new_value_alloced, oldval, errbuf,
|
||||
|
||||
if (curwin->w_curswant != MAXCOL)
|
||||
curwin->w_set_curswant = TRUE; /* in case 'showbreak' changed */
|
||||
check_redraw(options[opt_idx].flags);
|
||||
#ifdef FEAT_GUI
|
||||
/* check redraw when it's not a GUI option or the GUI is active. */
|
||||
if (!redraw_gui_only || gui.in_use)
|
||||
#endif
|
||||
check_redraw(options[opt_idx].flags);
|
||||
|
||||
return errmsg;
|
||||
}
|
||||
@@ -7185,22 +7256,28 @@ set_bool_option(opt_idx, varp, value, opt_flags)
|
||||
curbuf->b_did_warn = FALSE;
|
||||
|
||||
#ifdef FEAT_TITLE
|
||||
need_maketitle = TRUE;
|
||||
redraw_titles();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef FEAT_TITLE
|
||||
/* when 'modifiable' is changed, redraw the window title */
|
||||
else if ((int *)varp == &curbuf->b_p_ma)
|
||||
need_maketitle = TRUE;
|
||||
{
|
||||
redraw_titles();
|
||||
}
|
||||
/* when 'endofline' is changed, redraw the window title */
|
||||
else if ((int *)varp == &curbuf->b_p_eol)
|
||||
need_maketitle = TRUE;
|
||||
#ifdef FEAT_MBYTE
|
||||
/* when 'bomb' is changed, redraw the window title */
|
||||
{
|
||||
redraw_titles();
|
||||
}
|
||||
# ifdef FEAT_MBYTE
|
||||
/* when 'bomb' is changed, redraw the window title and tab page text */
|
||||
else if ((int *)varp == &curbuf->b_p_bomb)
|
||||
need_maketitle = TRUE;
|
||||
#endif
|
||||
{
|
||||
redraw_titles();
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* when 'bin' is set also set some other options */
|
||||
@@ -7208,7 +7285,7 @@ set_bool_option(opt_idx, varp, value, opt_flags)
|
||||
{
|
||||
set_options_bin(old_value, curbuf->b_p_bin, opt_flags);
|
||||
#ifdef FEAT_TITLE
|
||||
need_maketitle = TRUE;
|
||||
redraw_titles();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -7393,7 +7470,7 @@ set_bool_option(opt_idx, varp, value, opt_flags)
|
||||
if (!value)
|
||||
save_file_ff(curbuf); /* Buffer is unchanged */
|
||||
#ifdef FEAT_TITLE
|
||||
need_maketitle = TRUE;
|
||||
redraw_titles();
|
||||
#endif
|
||||
#ifdef FEAT_AUTOCMD
|
||||
modified_was_set = value;
|
||||
@@ -7600,9 +7677,13 @@ set_bool_option(opt_idx, varp, value, opt_flags)
|
||||
* set. */
|
||||
if (STRCMP(p_enc, "utf-8") != 0)
|
||||
{
|
||||
static char *w_arabic = N_("W17: Arabic requires UTF-8, do ':set encoding=utf-8'");
|
||||
|
||||
msg_source(hl_attr(HLF_W));
|
||||
MSG_ATTR(_("W17: Arabic requires UTF-8, do ':set encoding=utf-8'"),
|
||||
hl_attr(HLF_W));
|
||||
MSG_ATTR(_(w_arabic), hl_attr(HLF_W));
|
||||
#ifdef FEAT_EVAL
|
||||
set_vim_var_string(VV_WARNINGMSG, (char_u *)_(w_arabic), -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
# ifdef FEAT_MBYTE
|
||||
@@ -7828,7 +7909,7 @@ set_num_option(opt_idx, varp, value, errbuf, errbuflen, opt_flags)
|
||||
newFoldLevel();
|
||||
}
|
||||
|
||||
/* 'foldminlevel' */
|
||||
/* 'foldminlines' */
|
||||
else if (pp == &curwin->w_p_fml)
|
||||
{
|
||||
foldUpdateAll(curwin);
|
||||
@@ -10232,25 +10313,110 @@ wc_use_keyname(varp, wcp)
|
||||
|
||||
#ifdef FEAT_LANGMAP
|
||||
/*
|
||||
* Any character has an equivalent character. This is used for keyboards that
|
||||
* have a special language mode that sends characters above 128 (although
|
||||
* other characters can be translated too).
|
||||
* Any character has an equivalent 'langmap' character. This is used for
|
||||
* keyboards that have a special language mode that sends characters above
|
||||
* 128 (although other characters can be translated too). The "to" field is a
|
||||
* Vim command character. This avoids having to switch the keyboard back to
|
||||
* ASCII mode when leaving Insert mode.
|
||||
*
|
||||
* langmap_mapchar[] maps any of 256 chars to an ASCII char used for Vim
|
||||
* commands.
|
||||
* When FEAT_MBYTE is defined langmap_mapga.ga_data is a sorted table of
|
||||
* langmap_entry_T. This does the same as langmap_mapchar[] for characters >=
|
||||
* 256.
|
||||
*/
|
||||
# ifdef FEAT_MBYTE
|
||||
/*
|
||||
* With multi-byte support use growarray for 'langmap' chars >= 256
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int from;
|
||||
int to;
|
||||
} langmap_entry_T;
|
||||
|
||||
static garray_T langmap_mapga;
|
||||
static void langmap_set_entry __ARGS((int from, int to));
|
||||
|
||||
/*
|
||||
* char_u langmap_mapchar[256];
|
||||
* Normally maps each of the 128 upper chars to an <128 ascii char; used to
|
||||
* "translate" native lang chars in normal mode or some cases of
|
||||
* insert mode without having to tediously switch lang mode back&forth.
|
||||
* Search for an entry in "langmap_mapga" for "from". If found set the "to"
|
||||
* field. If not found insert a new entry at the appropriate location.
|
||||
*/
|
||||
static void
|
||||
langmap_set_entry(from, to)
|
||||
int from;
|
||||
int to;
|
||||
{
|
||||
langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data);
|
||||
int a = 0;
|
||||
int b = langmap_mapga.ga_len;
|
||||
|
||||
/* Do a binary search for an existing entry. */
|
||||
while (a != b)
|
||||
{
|
||||
int i = (a + b) / 2;
|
||||
int d = entries[i].from - from;
|
||||
|
||||
if (d == 0)
|
||||
{
|
||||
entries[i].to = to;
|
||||
return;
|
||||
}
|
||||
if (d < 0)
|
||||
a = i + 1;
|
||||
else
|
||||
b = i;
|
||||
}
|
||||
|
||||
if (ga_grow(&langmap_mapga, 1) != OK)
|
||||
return; /* out of memory */
|
||||
|
||||
/* insert new entry at position "a" */
|
||||
entries = (langmap_entry_T *)(langmap_mapga.ga_data) + a;
|
||||
mch_memmove(entries + 1, entries,
|
||||
(langmap_mapga.ga_len - a) * sizeof(langmap_entry_T));
|
||||
++langmap_mapga.ga_len;
|
||||
entries[0].from = from;
|
||||
entries[0].to = to;
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply 'langmap' to multi-byte character "c" and return the result.
|
||||
*/
|
||||
int
|
||||
langmap_adjust_mb(c)
|
||||
int c;
|
||||
{
|
||||
langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data);
|
||||
int a = 0;
|
||||
int b = langmap_mapga.ga_len;
|
||||
|
||||
while (a != b)
|
||||
{
|
||||
int i = (a + b) / 2;
|
||||
int d = entries[i].from - c;
|
||||
|
||||
if (d == 0)
|
||||
return entries[i].to; /* found matching entry */
|
||||
if (d < 0)
|
||||
a = i + 1;
|
||||
else
|
||||
b = i;
|
||||
}
|
||||
return c; /* no entry found, return "c" unmodified */
|
||||
}
|
||||
# endif
|
||||
|
||||
static void
|
||||
langmap_init()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 256; i++) /* we init with a-one-to one map */
|
||||
langmap_mapchar[i] = i;
|
||||
for (i = 0; i < 256; i++)
|
||||
langmap_mapchar[i] = i; /* we init with a one-to-one map */
|
||||
# ifdef FEAT_MBYTE
|
||||
ga_init2(&langmap_mapga, sizeof(langmap_entry_T), 8);
|
||||
# endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -10264,7 +10430,10 @@ langmap_set()
|
||||
char_u *p2;
|
||||
int from, to;
|
||||
|
||||
langmap_init(); /* back to one-to-one map first */
|
||||
#ifdef FEAT_MBYTE
|
||||
ga_clear(&langmap_mapga); /* clear the previous map first */
|
||||
#endif
|
||||
langmap_init(); /* back to one-to-one map */
|
||||
|
||||
for (p = p_langmap; p[0] != NUL; )
|
||||
{
|
||||
@@ -10314,7 +10483,13 @@ langmap_set()
|
||||
transchar(from));
|
||||
return;
|
||||
}
|
||||
langmap_mapchar[from & 255] = to;
|
||||
|
||||
#ifdef FEAT_MBYTE
|
||||
if (from >= 256)
|
||||
langmap_set_entry(from, to);
|
||||
else
|
||||
#endif
|
||||
langmap_mapchar[from & 255] = to;
|
||||
|
||||
/* Advance to next pair */
|
||||
mb_ptr_adv(p);
|
||||
|
||||
@@ -609,3 +609,67 @@ mch_textdomain(const char *domain)
|
||||
return (char*)domain;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void macosx_fork()
|
||||
{
|
||||
pid_t pid;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* On OS X, you have to exec after a fork, otherwise calls to frameworks
|
||||
* will assert (and without Core Foundation, you can't start the gui. What
|
||||
* fun.). See CAVEATS at:
|
||||
*
|
||||
* http://developer.apple.com/documentation/Darwin/Reference/ManPages/
|
||||
* man2/fork.2.html
|
||||
*
|
||||
* Since we have to go through this anyways, we might as well use vfork.
|
||||
* But: then we can't detach from our starting shell, so stick with fork.
|
||||
*/
|
||||
|
||||
/* Stolen from http://paste.lisp.org/display/50906 */
|
||||
extern int *_NSGetArgc(void);
|
||||
extern char ***_NSGetArgv(void);
|
||||
|
||||
int argc = *_NSGetArgc();
|
||||
char ** argv = *_NSGetArgv();
|
||||
char * newargv[argc+2];
|
||||
|
||||
newargv[0] = argv[0];
|
||||
|
||||
/*
|
||||
* Make sure "-f" is in front of potential "--remote" flags, else
|
||||
* they would consume it.
|
||||
*/
|
||||
newargv[1] = "-f";
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
newargv[i + 1] = argv[i];
|
||||
}
|
||||
newargv[argc+1] = NULL;
|
||||
|
||||
pid = fork();
|
||||
switch(pid) {
|
||||
case -1:
|
||||
# ifndef NDEBUG
|
||||
fprintf(stderr, "vim: Mac OS X workaround fork() failed!");
|
||||
# endif
|
||||
_exit(255);
|
||||
case 0:
|
||||
/* Child. */
|
||||
|
||||
/* Make sure we survive our shell */
|
||||
setsid();
|
||||
|
||||
/* Restarts the vim process, will not return. */
|
||||
execvp(argv[0], newargv);
|
||||
|
||||
/* If we come here, exec has failed. bail. */
|
||||
_exit(255);
|
||||
default:
|
||||
/* Parent */
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
+21
-2
@@ -1223,6 +1223,25 @@ utf16_to_enc(short_u *str, int *lenp)
|
||||
}
|
||||
#endif /* FEAT_MBYTE */
|
||||
|
||||
/*
|
||||
* Wait for another process to Close the Clipboard.
|
||||
* Returns TRUE for success.
|
||||
*/
|
||||
int
|
||||
vim_open_clipboard()
|
||||
{
|
||||
int delay = 10;
|
||||
|
||||
while (!OpenClipboard(NULL))
|
||||
{
|
||||
if (delay > 500)
|
||||
return FALSE; /* waited too long, give up */
|
||||
Sleep(delay);
|
||||
delay *= 2; /* wait for 10, 20, 40, 80, etc. msec */
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the current selection and put it in the clipboard register.
|
||||
*
|
||||
@@ -1254,7 +1273,7 @@ clip_mch_request_selection(VimClipboard *cbd)
|
||||
* Don't pass GetActiveWindow() as an argument to OpenClipboard() because
|
||||
* then we can't paste back into the same window for some reason - webb.
|
||||
*/
|
||||
if (!OpenClipboard(NULL))
|
||||
if (!vim_open_clipboard())
|
||||
return;
|
||||
|
||||
/* Check for vim's own clipboard format first. This only gets the type of
|
||||
@@ -1562,7 +1581,7 @@ clip_mch_set_selection(VimClipboard *cbd)
|
||||
* because then we can't paste back into the same window for some
|
||||
* reason - webb.
|
||||
*/
|
||||
if (OpenClipboard(NULL))
|
||||
if (vim_open_clipboard())
|
||||
{
|
||||
if (EmptyClipboard())
|
||||
{
|
||||
|
||||
+93
-28
@@ -181,7 +181,8 @@ static RETSIGTYPE catch_sigpwr __ARGS(SIGPROTOARG);
|
||||
&& defined(FEAT_TITLE) && !defined(FEAT_GUI_GTK)
|
||||
# define SET_SIG_ALARM
|
||||
static RETSIGTYPE sig_alarm __ARGS(SIGPROTOARG);
|
||||
static int sig_alarm_called;
|
||||
/* volatile because it is used in signal handler sig_alarm(). */
|
||||
static volatile int sig_alarm_called;
|
||||
#endif
|
||||
static RETSIGTYPE deathtrap __ARGS(SIGPROTOARG);
|
||||
|
||||
@@ -201,13 +202,16 @@ static int save_patterns __ARGS((int num_pat, char_u **pat, int *num_file, char_
|
||||
# define SIG_ERR ((RETSIGTYPE (*)())-1)
|
||||
#endif
|
||||
|
||||
static int do_resize = FALSE;
|
||||
/* volatile because it is used in signal handler sig_winch(). */
|
||||
static volatile int do_resize = FALSE;
|
||||
#ifndef __EMX__
|
||||
static char_u *extra_shell_arg = NULL;
|
||||
static int show_shell_mess = TRUE;
|
||||
#endif
|
||||
static int deadly_signal = 0; /* The signal we caught */
|
||||
static int in_mch_delay = FALSE; /* sleeping in mch_delay() */
|
||||
/* volatile because it is used in signal handler deathtrap(). */
|
||||
static volatile int deadly_signal = 0; /* The signal we caught */
|
||||
/* volatile because it is used in signal handler deathtrap(). */
|
||||
static volatile int in_mch_delay = FALSE; /* sleeping in mch_delay() */
|
||||
|
||||
static int curr_tmode = TMODE_COOK; /* contains current terminal mode */
|
||||
|
||||
@@ -802,7 +806,7 @@ init_signal_stack()
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We need correct potatotypes for a signal function, otherwise mean compilers
|
||||
* We need correct prototypes for a signal function, otherwise mean compilers
|
||||
* will barf when the second argument to signal() is ``wrong''.
|
||||
* Let me try it with a few tricky defines from my own osdef.h (jw).
|
||||
*/
|
||||
@@ -1068,13 +1072,18 @@ deathtrap SIGDEFARG(sigarg)
|
||||
SIGRETURN;
|
||||
}
|
||||
|
||||
#ifdef _REENTRANT
|
||||
#if defined(_REENTRANT) && defined(SIGCONT)
|
||||
/*
|
||||
* On Solaris with multi-threading, suspending might not work immediately.
|
||||
* Catch the SIGCONT signal, which will be used as an indication whether the
|
||||
* suspending has been done or not.
|
||||
*
|
||||
* On Linux, signal is not always handled immediately either.
|
||||
* See https://bugs.launchpad.net/bugs/291373
|
||||
*
|
||||
* volatile because it is used in in signal handler sigcont_handler().
|
||||
*/
|
||||
static int sigcont_received;
|
||||
static volatile int sigcont_received;
|
||||
static RETSIGTYPE sigcont_handler __ARGS(SIGPROTOARG);
|
||||
|
||||
/*
|
||||
@@ -1118,15 +1127,28 @@ mch_suspend()
|
||||
}
|
||||
# endif
|
||||
|
||||
# ifdef _REENTRANT
|
||||
# if defined(_REENTRANT) && defined(SIGCONT)
|
||||
sigcont_received = FALSE;
|
||||
# endif
|
||||
kill(0, SIGTSTP); /* send ourselves a STOP signal */
|
||||
# ifdef _REENTRANT
|
||||
/* When we didn't suspend immediately in the kill(), do it now. Happens
|
||||
* on multi-threaded Solaris. */
|
||||
if (!sigcont_received)
|
||||
pause();
|
||||
# if defined(_REENTRANT) && defined(SIGCONT)
|
||||
/*
|
||||
* Wait for the SIGCONT signal to be handled. It generally happens
|
||||
* immediately, but somehow not all the time. Do not call pause()
|
||||
* because there would be race condition which would hang Vim if
|
||||
* signal happened in between the test of sigcont_received and the
|
||||
* call to pause(). If signal is not yet received, call sleep(0)
|
||||
* to just yield CPU. Signal should then be received. If somehow
|
||||
* it's still not received, sleep 1, 2, 3 ms. Don't bother waiting
|
||||
* further if signal is not received after 1+2+3+4 ms (not expected
|
||||
* to happen).
|
||||
*/
|
||||
{
|
||||
long wait;
|
||||
for (wait = 0; !sigcont_received && wait <= 3L; wait++)
|
||||
/* Loop is not entered most of the time */
|
||||
mch_delay(wait, FALSE);
|
||||
}
|
||||
# endif
|
||||
|
||||
# ifdef FEAT_TITLE
|
||||
@@ -1175,7 +1197,7 @@ set_signals()
|
||||
#ifdef SIGTSTP
|
||||
signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
|
||||
#endif
|
||||
#ifdef _REENTRANT
|
||||
#if defined(_REENTRANT) && defined(SIGCONT)
|
||||
signal(SIGCONT, sigcont_handler);
|
||||
#endif
|
||||
|
||||
@@ -1234,7 +1256,7 @@ catch_int_signal()
|
||||
reset_signals()
|
||||
{
|
||||
catch_signals(SIG_DFL, SIG_DFL);
|
||||
#ifdef _REENTRANT
|
||||
#if defined(_REENTRANT) && defined(SIGCONT)
|
||||
/* SIGCONT isn't in the list, because its default action is ignore */
|
||||
signal(SIGCONT, SIG_DFL);
|
||||
#endif
|
||||
@@ -3952,7 +3974,17 @@ mch_call_shell(cmd, options)
|
||||
* children can be kill()ed. Don't do this when using pipes,
|
||||
* because stdin is not a tty, we would lose /dev/tty. */
|
||||
if (p_stmp)
|
||||
{
|
||||
(void)setsid();
|
||||
# if defined(SIGHUP)
|
||||
/* When doing "!xterm&" and 'shell' is bash: the shell
|
||||
* will exit and send SIGHUP to all processes in its
|
||||
* group, killing the just started process. Ignore SIGHUP
|
||||
* to avoid that. (suggested by Simon Schubert)
|
||||
*/
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
# endif
|
||||
}
|
||||
# endif
|
||||
# ifdef FEAT_GUI
|
||||
if (pty_slave_fd >= 0)
|
||||
@@ -4084,6 +4116,9 @@ mch_call_shell(cmd, options)
|
||||
int fromshell_fd;
|
||||
garray_T ga;
|
||||
int noread_cnt;
|
||||
# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
|
||||
struct timeval start_tv;
|
||||
# endif
|
||||
|
||||
# ifdef FEAT_GUI
|
||||
if (pty_master_fd >= 0)
|
||||
@@ -4193,7 +4228,9 @@ mch_call_shell(cmd, options)
|
||||
ga_init2(&ga, 1, BUFLEN);
|
||||
|
||||
noread_cnt = 0;
|
||||
|
||||
# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
|
||||
gettimeofday(&start_tv, NULL);
|
||||
# endif
|
||||
for (;;)
|
||||
{
|
||||
/*
|
||||
@@ -4206,25 +4243,34 @@ mch_call_shell(cmd, options)
|
||||
* that a typed password is echoed for ssh or gpg command.
|
||||
* Don't get characters when the child has already
|
||||
* finished (wait_pid == 0).
|
||||
* Don't get extra characters when we already have one.
|
||||
* Don't read characters unless we didn't get output for a
|
||||
* while, avoids that ":r !ls" eats typeahead.
|
||||
* while (noread_cnt > 4), avoids that ":r !ls" eats
|
||||
* typeahead.
|
||||
*/
|
||||
len = 0;
|
||||
if (!(options & SHELL_EXPAND)
|
||||
&& ((options &
|
||||
(SHELL_READ|SHELL_WRITE|SHELL_COOKED))
|
||||
!= (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
|
||||
#ifdef FEAT_GUI
|
||||
# ifdef FEAT_GUI
|
||||
|| gui.in_use
|
||||
#endif
|
||||
# endif
|
||||
)
|
||||
&& wait_pid == 0
|
||||
&& (ta_len > 0
|
||||
|| (noread_cnt > 4
|
||||
&& (len = ui_inchar(ta_buf,
|
||||
BUFLEN, 10L, 0)) > 0)))
|
||||
&& (ta_len > 0 || noread_cnt > 4))
|
||||
{
|
||||
if (ta_len == 0)
|
||||
{
|
||||
/* Get extra characters when we don't have any.
|
||||
* Reset the counter and timer. */
|
||||
noread_cnt = 0;
|
||||
# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
|
||||
gettimeofday(&start_tv, NULL);
|
||||
# endif
|
||||
len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
|
||||
}
|
||||
if (ta_len > 0 || len > 0)
|
||||
{
|
||||
/*
|
||||
* For pipes:
|
||||
* Check for CTRL-C: send interrupt signal to child.
|
||||
@@ -4326,9 +4372,9 @@ mch_call_shell(cmd, options)
|
||||
{
|
||||
ta_len -= len;
|
||||
mch_memmove(ta_buf, ta_buf + len, ta_len);
|
||||
noread_cnt = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (got_int)
|
||||
@@ -4435,13 +4481,30 @@ mch_call_shell(cmd, options)
|
||||
cursor_on();
|
||||
out_flush();
|
||||
# if FEAT_GUI_MACVIM
|
||||
if (gui.in_use) {
|
||||
fast_breakcheck();
|
||||
if (gui.in_use)
|
||||
gui_macvim_flush();
|
||||
}
|
||||
# endif
|
||||
if (got_int)
|
||||
break;
|
||||
|
||||
# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
|
||||
{
|
||||
struct timeval now_tv;
|
||||
long msec;
|
||||
|
||||
/* Avoid that we keep looping here without
|
||||
* checking for a CTRL-C for a long time. Don't
|
||||
* break out too often to avoid losing typeahead. */
|
||||
gettimeofday(&now_tv, NULL);
|
||||
msec = (now_tv.tv_sec - start_tv.tv_sec) * 1000L
|
||||
+ (now_tv.tv_usec - start_tv.tv_usec) / 1000L;
|
||||
if (msec > 2000)
|
||||
{
|
||||
noread_cnt = 5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
/* If we already detected the child has finished break the
|
||||
@@ -5864,7 +5927,9 @@ gpm_open()
|
||||
* we are going to suspend or starting an external process
|
||||
* so we shouldn't have problem with this
|
||||
*/
|
||||
# ifdef SIGTSTP
|
||||
signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
|
||||
# endif
|
||||
return 1; /* succeed */
|
||||
}
|
||||
if (gpm_fd == -2)
|
||||
|
||||
@@ -263,6 +263,9 @@ extern char *vim_SelFile __ARGS((Widget toplevel, char *prompt, char *init_path,
|
||||
#ifdef MACOS_CONVERT
|
||||
# include "os_mac_conv.pro"
|
||||
#endif
|
||||
#ifdef MACOS_X
|
||||
# include "os_macosx.pro"
|
||||
#endif
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
# define _PROTO_H
|
||||
|
||||
@@ -40,6 +40,7 @@ void global_exe __ARGS((char_u *cmd));
|
||||
int read_viminfo_sub_string __ARGS((vir_T *virp, int force));
|
||||
void write_viminfo_sub_string __ARGS((FILE *fp));
|
||||
void free_old_sub __ARGS((void));
|
||||
void free_signs __ARGS((void));
|
||||
int prepare_tagpreview __ARGS((int undo_sync));
|
||||
void ex_help __ARGS((exarg_T *eap));
|
||||
char_u *check_help_lang __ARGS((char_u *arg));
|
||||
|
||||
@@ -4,6 +4,7 @@ char_u *getcmdline_prompt __ARGS((int firstc, char_u *prompt, int attr, int xp_c
|
||||
int text_locked __ARGS((void));
|
||||
void text_locked_msg __ARGS((void));
|
||||
int curbuf_locked __ARGS((void));
|
||||
int allbuf_locked __ARGS((void));
|
||||
char_u *getexline __ARGS((int c, void *dummy, int indent));
|
||||
char_u *getexmodeline __ARGS((int promptc, void *dummy, int indent));
|
||||
int cmdline_overstrike __ARGS((void));
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/* if_cscope.c */
|
||||
char_u *get_cscope_name __ARGS((expand_T *xp, int idx));
|
||||
void set_context_in_cscope_cmd __ARGS((expand_T *xp, char_u *arg));
|
||||
void do_cscope __ARGS((exarg_T *eap));
|
||||
void do_scscope __ARGS((exarg_T *eap));
|
||||
void do_cstag __ARGS((exarg_T *eap));
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/* main.c */
|
||||
void main_loop __ARGS((int cmdwin, int noexmode));
|
||||
void prepare_getout __ARGS(());
|
||||
void getout_preserve_modified __ARGS((int exitval));
|
||||
void getout __ARGS((int exitval));
|
||||
int process_env __ARGS((char_u *env, int is_viminit));
|
||||
|
||||
@@ -11,7 +11,7 @@ void netbeans_send_disconnect __ARGS((void));
|
||||
void netbeans_frame_moved __ARGS((int new_x, int new_y));
|
||||
void netbeans_file_activated __ARGS((buf_T *bufp));
|
||||
void netbeans_file_opened __ARGS((buf_T *bufp));
|
||||
void netbeans_file_closed __ARGS((buf_T *bufp));
|
||||
void netbeans_file_killed __ARGS((buf_T *bufp));
|
||||
void netbeans_inserted __ARGS((buf_T *bufp, linenr_T linenr, colnr_T col, char_u *txt, int newlen));
|
||||
void netbeans_removed __ARGS((buf_T *bufp, linenr_T linenr, colnr_T col, long len));
|
||||
void netbeans_unmodified __ARGS((buf_T *bufp));
|
||||
|
||||
@@ -44,6 +44,7 @@ void set_imsearch_global __ARGS((void));
|
||||
void set_context_in_set_cmd __ARGS((expand_T *xp, char_u *arg, int opt_flags));
|
||||
int ExpandSettings __ARGS((expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file));
|
||||
int ExpandOldSetting __ARGS((int *num_file, char_u ***file));
|
||||
int langmap_adjust_mb __ARGS((int c));
|
||||
int has_format_option __ARGS((int x));
|
||||
int shortmess __ARGS((int x));
|
||||
void vimrc_found __ARGS((char_u *fname, char_u *envname));
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
/* os_macosx.pro */
|
||||
void macosx_fork __ARGS((void));
|
||||
/* vim: set ft=c : */
|
||||
+14
-12
@@ -1419,6 +1419,7 @@ qf_jump(qi, dir, errornr, forceit)
|
||||
int opened_window = FALSE;
|
||||
win_T *win;
|
||||
win_T *altwin;
|
||||
int flags;
|
||||
#endif
|
||||
win_T *oldwin = curwin;
|
||||
int print_message = TRUE;
|
||||
@@ -1531,7 +1532,6 @@ qf_jump(qi, dir, errornr, forceit)
|
||||
if (qf_ptr->qf_type == 1 && (!curwin->w_buffer->b_help || cmdmod.tab != 0))
|
||||
{
|
||||
win_T *wp;
|
||||
int n;
|
||||
|
||||
if (cmdmod.tab != 0)
|
||||
wp = NULL;
|
||||
@@ -1547,13 +1547,16 @@ qf_jump(qi, dir, errornr, forceit)
|
||||
* Split off help window; put it at far top if no position
|
||||
* specified, the current window is vertically split and narrow.
|
||||
*/
|
||||
n = WSP_HELP;
|
||||
flags = WSP_HELP;
|
||||
# ifdef FEAT_VERTSPLIT
|
||||
if (cmdmod.split == 0 && curwin->w_width != Columns
|
||||
&& curwin->w_width < 80)
|
||||
n |= WSP_TOP;
|
||||
flags |= WSP_TOP;
|
||||
# endif
|
||||
if (win_split(0, n) == FAIL)
|
||||
if (qi != &ql_info)
|
||||
flags |= WSP_NEWLOC; /* don't copy the location list */
|
||||
|
||||
if (win_split(0, flags) == FAIL)
|
||||
goto theend;
|
||||
opened_window = TRUE; /* close it when fail */
|
||||
|
||||
@@ -1563,7 +1566,6 @@ qf_jump(qi, dir, errornr, forceit)
|
||||
if (qi != &ql_info) /* not a quickfix list */
|
||||
{
|
||||
/* The new window should use the supplied location list */
|
||||
qf_free_all(curwin);
|
||||
curwin->w_llist = qi;
|
||||
qi->qf_refcount++;
|
||||
}
|
||||
@@ -1610,10 +1612,11 @@ qf_jump(qi, dir, errornr, forceit)
|
||||
{
|
||||
goto_tabpage_win(tp, wp);
|
||||
usable_win = 1;
|
||||
break;
|
||||
goto win_found;
|
||||
}
|
||||
}
|
||||
}
|
||||
win_found:
|
||||
|
||||
/*
|
||||
* If there is only one window and it is the quickfix window, create a
|
||||
@@ -1623,7 +1626,10 @@ qf_jump(qi, dir, errornr, forceit)
|
||||
{
|
||||
ll_ref = curwin->w_llist_ref;
|
||||
|
||||
if (win_split(0, WSP_ABOVE) == FAIL)
|
||||
flags = WSP_ABOVE;
|
||||
if (ll_ref != NULL)
|
||||
flags |= WSP_NEWLOC;
|
||||
if (win_split(0, flags) == FAIL)
|
||||
goto failed; /* not enough room for window */
|
||||
opened_window = TRUE; /* close it when fail */
|
||||
p_swb = empty_option; /* don't split again */
|
||||
@@ -1635,7 +1641,6 @@ qf_jump(qi, dir, errornr, forceit)
|
||||
{
|
||||
/* The new window should use the location list from the
|
||||
* location list window */
|
||||
qf_free_all(curwin);
|
||||
curwin->w_llist = ll_ref;
|
||||
ll_ref->qf_refcount++;
|
||||
}
|
||||
@@ -2310,15 +2315,12 @@ ex_copen(eap)
|
||||
if (eap->cmdidx == CMD_copen || eap->cmdidx == CMD_cwindow)
|
||||
/* Create the new window at the very bottom. */
|
||||
win_goto(lastwin);
|
||||
if (win_split(height, WSP_BELOW) == FAIL)
|
||||
if (win_split(height, WSP_BELOW | WSP_NEWLOC) == FAIL)
|
||||
return; /* not enough room for window */
|
||||
#ifdef FEAT_SCROLLBIND
|
||||
curwin->w_p_scb = FALSE;
|
||||
#endif
|
||||
|
||||
/* Remove the location list for the quickfix window */
|
||||
qf_free_all(curwin);
|
||||
|
||||
if (eap->cmdidx == CMD_lopen || eap->cmdidx == CMD_lwindow)
|
||||
{
|
||||
/*
|
||||
|
||||
+4
-6
@@ -4532,7 +4532,7 @@ regmatch(scan)
|
||||
cleanup_subexpr();
|
||||
if (!REG_MULTI) /* Single-line regexp */
|
||||
{
|
||||
if (reg_endp[no] == NULL)
|
||||
if (reg_startp[no] == NULL || reg_endp[no] == NULL)
|
||||
{
|
||||
/* Backref was not set: Match an empty string. */
|
||||
len = 0;
|
||||
@@ -4548,7 +4548,7 @@ regmatch(scan)
|
||||
}
|
||||
else /* Multi-line regexp */
|
||||
{
|
||||
if (reg_endpos[no].lnum < 0)
|
||||
if (reg_startpos[no].lnum < 0 || reg_endpos[no].lnum < 0)
|
||||
{
|
||||
/* Backref was not set: Match an empty string. */
|
||||
len = 0;
|
||||
@@ -7279,13 +7279,11 @@ reg_submatch(no)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (submatch_match->endp[no] == NULL)
|
||||
s = submatch_match->startp[no];
|
||||
if (s == NULL || submatch_match->endp[no] == NULL)
|
||||
retval = NULL;
|
||||
else
|
||||
{
|
||||
s = submatch_match->startp[no];
|
||||
retval = vim_strnsave(s, (int)(submatch_match->endp[no] - s));
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
||||
+98
-41
@@ -2596,6 +2596,7 @@ win_line(wp, lnum, startrow, endrow, nochange)
|
||||
int noinvcur = FALSE; /* don't invert the cursor */
|
||||
#ifdef FEAT_VISUAL
|
||||
pos_T *top, *bot;
|
||||
int lnum_in_visual_area = FALSE;
|
||||
#endif
|
||||
pos_T pos;
|
||||
long v;
|
||||
@@ -2792,9 +2793,10 @@ win_line(wp, lnum, startrow, endrow, nochange)
|
||||
top = &VIsual;
|
||||
bot = &curwin->w_cursor;
|
||||
}
|
||||
lnum_in_visual_area = (lnum >= top->lnum && lnum <= bot->lnum);
|
||||
if (VIsual_mode == Ctrl_V) /* block mode */
|
||||
{
|
||||
if (lnum >= top->lnum && lnum <= bot->lnum)
|
||||
if (lnum_in_visual_area)
|
||||
{
|
||||
fromcol = wp->w_old_cursor_fcol;
|
||||
tocol = wp->w_old_cursor_lcol;
|
||||
@@ -2887,8 +2889,9 @@ win_line(wp, lnum, startrow, endrow, nochange)
|
||||
}
|
||||
else
|
||||
tocol = MAXCOL;
|
||||
if (fromcol == tocol) /* do at least one character */
|
||||
tocol = fromcol + 1; /* happens when past end of line */
|
||||
/* do at least one character; happens when past end of line */
|
||||
if (fromcol == tocol)
|
||||
tocol = fromcol + 1;
|
||||
area_highlighting = TRUE;
|
||||
attr = hl_attr(HLF_I);
|
||||
}
|
||||
@@ -3420,6 +3423,7 @@ win_line(wp, lnum, startrow, endrow, nochange)
|
||||
&& (*mb_ptr2cells)(ptr) > 1)
|
||||
#endif
|
||||
|| ((int)vcol_prev == fromcol_prev
|
||||
&& vcol_prev < vcol /* not at margin */
|
||||
&& vcol < tocol))
|
||||
area_attr = attr; /* start highlighting */
|
||||
else if (area_attr != 0
|
||||
@@ -3552,7 +3556,8 @@ win_line(wp, lnum, startrow, endrow, nochange)
|
||||
/* Use line_attr when not in the Visual or 'incsearch' area
|
||||
* (area_attr may be 0 when "noinvcur" is set). */
|
||||
else if (line_attr != 0 && ((fromcol == -10 && tocol == MAXCOL)
|
||||
|| (vcol < fromcol || vcol >= tocol)))
|
||||
|| vcol < fromcol || vcol_prev < fromcol_prev
|
||||
|| vcol >= tocol))
|
||||
char_attr = line_attr;
|
||||
#endif
|
||||
else
|
||||
@@ -4114,6 +4119,7 @@ win_line(wp, lnum, startrow, endrow, nochange)
|
||||
# endif
|
||||
(col < W_WIDTH(wp)))
|
||||
&& !(noinvcur
|
||||
&& lnum == wp->w_cursor.lnum
|
||||
&& (colnr_T)vcol == wp->w_virtcol)))
|
||||
&& lcs_eol_one >= 0)
|
||||
{
|
||||
@@ -4255,7 +4261,7 @@ win_line(wp, lnum, startrow, endrow, nochange)
|
||||
* preedit_changed and commit. Thus Vim can't set "im_is_active", use
|
||||
* im_is_preediting() here. */
|
||||
if (xic != NULL
|
||||
&& lnum == curwin->w_cursor.lnum
|
||||
&& lnum == wp->w_cursor.lnum
|
||||
&& (State & INSERT)
|
||||
&& !p_imdisable
|
||||
&& im_is_preediting()
|
||||
@@ -4264,7 +4270,7 @@ win_line(wp, lnum, startrow, endrow, nochange)
|
||||
colnr_T tcol;
|
||||
|
||||
if (preedit_end_col == MAXCOL)
|
||||
getvcol(curwin, &(curwin->w_cursor), &tcol, NULL, NULL);
|
||||
getvcol(curwin, &(wp->w_cursor), &tcol, NULL, NULL);
|
||||
else
|
||||
tcol = preedit_end_col;
|
||||
if ((long)preedit_start_col <= vcol && vcol < (long)tcol)
|
||||
@@ -4361,7 +4367,13 @@ win_line(wp, lnum, startrow, endrow, nochange)
|
||||
}
|
||||
#endif
|
||||
if (lcs_eol == lcs_eol_one
|
||||
&& ((area_attr != 0 && vcol == fromcol && c == NUL)
|
||||
&& ((area_attr != 0 && vcol == fromcol
|
||||
#ifdef FEAT_VISUAL
|
||||
&& (VIsual_mode != Ctrl_V
|
||||
|| lnum == VIsual.lnum
|
||||
|| lnum == curwin->w_cursor.lnum)
|
||||
#endif
|
||||
&& c == NUL)
|
||||
#ifdef FEAT_SEARCH_EXTRA
|
||||
/* highlight 'hlsearch' match at end of line */
|
||||
|| (prevcol_hl_flag == TRUE
|
||||
@@ -4455,7 +4467,8 @@ win_line(wp, lnum, startrow, endrow, nochange)
|
||||
if (c == NUL)
|
||||
{
|
||||
#ifdef FEAT_SYN_HL
|
||||
if (eol_hl_off > 0 && vcol - eol_hl_off == (long)wp->w_virtcol)
|
||||
if (eol_hl_off > 0 && vcol - eol_hl_off == (long)wp->w_virtcol
|
||||
&& lnum == wp->w_cursor.lnum)
|
||||
{
|
||||
/* highlight last char after line */
|
||||
--col;
|
||||
@@ -4557,7 +4570,8 @@ win_line(wp, lnum, startrow, endrow, nochange)
|
||||
* highlight the cursor position itself. */
|
||||
if (wp->w_p_cuc && vcol == (long)wp->w_virtcol
|
||||
&& lnum != wp->w_cursor.lnum
|
||||
&& draw_state == WL_LINE)
|
||||
&& draw_state == WL_LINE
|
||||
&& !lnum_in_visual_area)
|
||||
{
|
||||
vcol_save_attr = char_attr;
|
||||
char_attr = hl_combine_attr(char_attr, hl_attr(HLF_CUC));
|
||||
@@ -4660,7 +4674,7 @@ win_line(wp, lnum, startrow, endrow, nochange)
|
||||
--n_skip;
|
||||
|
||||
/* Only advance the "vcol" when after the 'number' column. */
|
||||
if (draw_state >= WL_SBR
|
||||
if (draw_state > WL_NR
|
||||
#ifdef FEAT_DIFF
|
||||
&& filler_todo <= 0
|
||||
#endif
|
||||
@@ -5127,8 +5141,8 @@ screen_line(row, coloff, endcol, clear_width
|
||||
#endif
|
||||
|
||||
#if defined(FEAT_GUI) || defined(UNIX)
|
||||
/* The bold trick makes a single row of pixels appear in the next
|
||||
* character. When a bold character is removed, the next
|
||||
/* The bold trick makes a single column of pixels appear in the
|
||||
* next character. When a bold character is removed, the next
|
||||
* character should be redrawn too. This happens for our own GUI
|
||||
* and for some xterms. */
|
||||
if (
|
||||
@@ -6271,9 +6285,15 @@ screen_puts_len(text, len, row, col, attr)
|
||||
int pcc[MAX_MCO];
|
||||
# endif
|
||||
#endif
|
||||
#if defined(FEAT_MBYTE) || defined(FEAT_GUI) || defined(UNIX)
|
||||
int force_redraw_this;
|
||||
int force_redraw_next = FALSE;
|
||||
#endif
|
||||
int need_redraw;
|
||||
|
||||
if (ScreenLines == NULL || row >= screen_Rows) /* safety check */
|
||||
return;
|
||||
off = LineOffset[row] + col;
|
||||
|
||||
#ifdef FEAT_MBYTE
|
||||
/* When drawing over the right halve of a double-wide char clear out the
|
||||
@@ -6283,10 +6303,21 @@ screen_puts_len(text, len, row, col, attr)
|
||||
&& !gui.in_use
|
||||
# endif
|
||||
&& mb_fix_col(col, row) != col)
|
||||
screen_puts_len((char_u *)" ", 1, row, col - 1, 0);
|
||||
{
|
||||
ScreenLines[off - 1] = ' ';
|
||||
ScreenAttrs[off - 1] = 0;
|
||||
if (enc_utf8)
|
||||
{
|
||||
ScreenLinesUC[off - 1] = 0;
|
||||
ScreenLinesC[0][off - 1] = 0;
|
||||
}
|
||||
/* redraw the previous cell, make it empty */
|
||||
screen_char(off - 1, row, col - 1);
|
||||
/* force the cell at "col" to be redrawn */
|
||||
force_redraw_next = TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
off = LineOffset[row] + col;
|
||||
#ifdef FEAT_MBYTE
|
||||
max_off = LineOffset[row] + screen_Columns;
|
||||
#endif
|
||||
@@ -6350,7 +6381,12 @@ screen_puts_len(text, len, row, col, attr)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ScreenLines[off] != c
|
||||
#if defined(FEAT_MBYTE) || defined(FEAT_GUI) || defined(UNIX)
|
||||
force_redraw_this = force_redraw_next;
|
||||
force_redraw_next = FALSE;
|
||||
#endif
|
||||
|
||||
need_redraw = ScreenLines[off] != c
|
||||
#ifdef FEAT_MBYTE
|
||||
|| (mbyte_cells == 2
|
||||
&& ScreenLines[off + 1] != (enc_dbcs ? ptr[1] : 0))
|
||||
@@ -6358,24 +6394,24 @@ screen_puts_len(text, len, row, col, attr)
|
||||
&& c == 0x8e
|
||||
&& ScreenLines2[off] != ptr[1])
|
||||
|| (enc_utf8
|
||||
&& (ScreenLinesUC[off] != (u8char_T)u8c
|
||||
&& (ScreenLinesUC[off] != (u8char_T)(c >= 0x80 ? u8c : 0)
|
||||
|| screen_comp_differs(off, u8cc)))
|
||||
#endif
|
||||
|| ScreenAttrs[off] != attr
|
||||
|| exmode_active
|
||||
|| exmode_active;
|
||||
|
||||
if (need_redraw
|
||||
#if defined(FEAT_MBYTE) || defined(FEAT_GUI) || defined(UNIX)
|
||||
|| force_redraw_this
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#if defined(FEAT_GUI) || defined(UNIX)
|
||||
/* The bold trick makes a single row of pixels appear in the next
|
||||
* character. When a bold character is removed, the next
|
||||
* character should be redrawn too. This happens for our own GUI
|
||||
* and for some xterms.
|
||||
* Force the redraw by setting the attribute to a different value
|
||||
* than "attr", the contents of ScreenLines[] may be needed by
|
||||
* mb_off2cells() further on.
|
||||
* Don't do this for the last drawn character, because the next
|
||||
* character may not be redrawn. */
|
||||
if (
|
||||
* and for some xterms. */
|
||||
if (need_redraw && ScreenLines[off] != ' ' && (
|
||||
# ifdef FEAT_GUI
|
||||
gui.in_use
|
||||
# endif
|
||||
@@ -6385,23 +6421,14 @@ screen_puts_len(text, len, row, col, attr)
|
||||
# ifdef UNIX
|
||||
term_is_xterm
|
||||
# endif
|
||||
)
|
||||
))
|
||||
{
|
||||
int n;
|
||||
int n = ScreenAttrs[off];
|
||||
|
||||
n = ScreenAttrs[off];
|
||||
# ifdef FEAT_MBYTE
|
||||
if (col + mbyte_cells < screen_Columns
|
||||
&& (n > HL_ALL || (n & HL_BOLD))
|
||||
&& (len < 0 ? ptr[mbyte_blen] != NUL
|
||||
: ptr + mbyte_blen < text + len))
|
||||
ScreenAttrs[off + mbyte_cells] = attr + 1;
|
||||
# else
|
||||
if (col + 1 < screen_Columns
|
||||
&& (n > HL_ALL || (n & HL_BOLD))
|
||||
&& (len < 0 ? ptr[1] != NUL : ptr + 1 < text + len))
|
||||
ScreenLines[off + 1] = 0;
|
||||
# endif
|
||||
if (n > HL_ALL)
|
||||
n = syn_attr2attr(n);
|
||||
if (n & HL_BOLD)
|
||||
force_redraw_next = TRUE;
|
||||
}
|
||||
#endif
|
||||
#ifdef FEAT_MBYTE
|
||||
@@ -6488,6 +6515,20 @@ screen_puts_len(text, len, row, col, attr)
|
||||
++ptr;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(FEAT_MBYTE) || defined(FEAT_GUI) || defined(UNIX)
|
||||
/* If we detected the next character needs to be redrawn, but the text
|
||||
* doesn't extend up to there, update the character here. */
|
||||
if (force_redraw_next && col < screen_Columns)
|
||||
{
|
||||
# ifdef FEAT_MBYTE
|
||||
if (enc_dbcs != 0 && dbcs_off2cells(off, max_off) > 1)
|
||||
screen_char_2(off, row, col);
|
||||
else
|
||||
# endif
|
||||
screen_char(off, row, col);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef FEAT_SEARCH_EXTRA
|
||||
@@ -7364,7 +7405,11 @@ screenalloc(clear)
|
||||
#endif
|
||||
static int entered = FALSE; /* avoid recursiveness */
|
||||
static int done_outofmem_msg = FALSE; /* did outofmem message */
|
||||
#ifdef FEAT_AUTOCMD
|
||||
int retry_count = 0;
|
||||
|
||||
retry:
|
||||
#endif
|
||||
/*
|
||||
* Allocation of the screen buffers is done only when the size changes and
|
||||
* when Rows and Columns have been set and we have started doing full
|
||||
@@ -7448,10 +7493,13 @@ screenalloc(clear)
|
||||
{
|
||||
outofmem = TRUE;
|
||||
#ifdef FEAT_WINDOWS
|
||||
break;
|
||||
goto give_up;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef FEAT_WINDOWS
|
||||
give_up:
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_MBYTE
|
||||
for (i = 0; i < p_mco; ++i)
|
||||
@@ -7636,8 +7684,17 @@ screenalloc(clear)
|
||||
--RedrawingDisabled;
|
||||
|
||||
#ifdef FEAT_AUTOCMD
|
||||
if (starting == 0)
|
||||
/*
|
||||
* Do not apply autocommands more than 3 times to avoid an endless loop
|
||||
* in case applying autocommands always changes Rows or Columns.
|
||||
*/
|
||||
if (starting == 0 && ++retry_count <= 3)
|
||||
{
|
||||
apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, FALSE, curbuf);
|
||||
/* In rare cases, autocommands may have altered Rows or Columns,
|
||||
* jump back to check if we need to allocate the screen again. */
|
||||
goto retry;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+6
-3
@@ -2376,7 +2376,7 @@ spell_move_to(wp, dir, allwords, curline, attrp)
|
||||
|
||||
/* If we are back at the starting line and there is no match then
|
||||
* give up. */
|
||||
if (lnum == wp->w_cursor.lnum && !found_one)
|
||||
if (lnum == wp->w_cursor.lnum && (!found_one || wrapped))
|
||||
break;
|
||||
|
||||
/* Skip the characters at the start of the next line that were
|
||||
@@ -4956,13 +4956,16 @@ typedef struct compitem_S
|
||||
* Structure that is used to store the items in the word tree. This avoids
|
||||
* the need to keep track of each allocated thing, everything is freed all at
|
||||
* once after ":mkspell" is done.
|
||||
* Note: "sb_next" must be just before "sb_data" to make sure the alignment of
|
||||
* "sb_data" is correct for systems where pointers must be aligned on
|
||||
* pointer-size boundaries and sizeof(pointer) > sizeof(int) (e.g., Sparc).
|
||||
*/
|
||||
#define SBLOCKSIZE 16000 /* size of sb_data */
|
||||
typedef struct sblock_S sblock_T;
|
||||
struct sblock_S
|
||||
{
|
||||
sblock_T *sb_next; /* next block in list */
|
||||
int sb_used; /* nr of bytes already in use */
|
||||
sblock_T *sb_next; /* next block in list */
|
||||
char_u sb_data[1]; /* data, actually longer */
|
||||
};
|
||||
|
||||
@@ -15011,7 +15014,7 @@ soundalike_score(goodstart, badstart)
|
||||
|
||||
case 0:
|
||||
/*
|
||||
* Lenghts are equal, thus changes must result in same length: An
|
||||
* Lengths are equal, thus changes must result in same length: An
|
||||
* insert is only possible in combination with a delete.
|
||||
* 1: check if for identical strings
|
||||
*/
|
||||
|
||||
@@ -515,7 +515,7 @@ do_tag(tag, type, count, forceit, verbose)
|
||||
* If a count is supplied to the ":tag <name>" command, then
|
||||
* jump to count'th matching tag.
|
||||
*/
|
||||
if (type == DT_TAG && count > 0)
|
||||
if (type == DT_TAG && *tag != NUL && count > 0)
|
||||
cur_match = count - 1;
|
||||
|
||||
if (type == DT_SELECT || type == DT_JUMP
|
||||
@@ -618,7 +618,7 @@ do_tag(tag, type, count, forceit, verbose)
|
||||
taglen_advance(taglen);
|
||||
MSG_PUTS_ATTR(_("file\n"), hl_attr(HLF_T));
|
||||
|
||||
for (i = 0; i < num_matches; ++i)
|
||||
for (i = 0; i < num_matches && !got_int; ++i)
|
||||
{
|
||||
parse_match(matches[i], &tagp);
|
||||
if (!new_tag && (
|
||||
@@ -655,6 +655,8 @@ do_tag(tag, type, count, forceit, verbose)
|
||||
}
|
||||
if (msg_col > 0)
|
||||
msg_putchar('\n');
|
||||
if (got_int)
|
||||
break;
|
||||
msg_advance(15);
|
||||
|
||||
/* print any extra fields */
|
||||
@@ -689,6 +691,8 @@ do_tag(tag, type, count, forceit, verbose)
|
||||
if (msg_col + ptr2cells(p) >= Columns)
|
||||
{
|
||||
msg_putchar('\n');
|
||||
if (got_int)
|
||||
break;
|
||||
msg_advance(15);
|
||||
}
|
||||
p = msg_outtrans_one(p, attr);
|
||||
@@ -704,6 +708,8 @@ do_tag(tag, type, count, forceit, verbose)
|
||||
if (msg_col > 15)
|
||||
{
|
||||
msg_putchar('\n');
|
||||
if (got_int)
|
||||
break;
|
||||
msg_advance(15);
|
||||
}
|
||||
}
|
||||
@@ -734,6 +740,8 @@ do_tag(tag, type, count, forceit, verbose)
|
||||
{
|
||||
if (msg_col + (*p == TAB ? 1 : ptr2cells(p)) > Columns)
|
||||
msg_putchar('\n');
|
||||
if (got_int)
|
||||
break;
|
||||
msg_advance(15);
|
||||
|
||||
/* skip backslash used for escaping command char */
|
||||
@@ -760,12 +768,9 @@ do_tag(tag, type, count, forceit, verbose)
|
||||
if (msg_col)
|
||||
msg_putchar('\n');
|
||||
ui_breakcheck();
|
||||
if (got_int)
|
||||
{
|
||||
got_int = FALSE; /* only stop the listing */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (got_int)
|
||||
got_int = FALSE; /* only stop the listing */
|
||||
ask_for_selection = TRUE;
|
||||
}
|
||||
#if defined(FEAT_QUICKFIX) && defined(FEAT_EVAL)
|
||||
@@ -2542,6 +2547,15 @@ free_tag_stuff()
|
||||
{
|
||||
ga_clear_strings(&tag_fnames);
|
||||
do_tag(NULL, DT_FREE, 0, 0, 0);
|
||||
tag_freematch();
|
||||
|
||||
# if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
|
||||
if (ptag_entry.tagname)
|
||||
{
|
||||
vim_free(ptag_entry.tagname);
|
||||
ptag_entry.tagname = NULL;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+9
-1
@@ -4920,7 +4920,15 @@ check_termcode(max_offset, buf, buflen)
|
||||
key_name[0] = KEY2TERMCAP0(key);
|
||||
key_name[1] = KEY2TERMCAP1(key);
|
||||
if (key_name[0] == KS_KEY)
|
||||
string[new_slen++] = key_name[1]; /* from ":set <M-b>=xx" */
|
||||
{
|
||||
/* from ":set <M-b>=xx" */
|
||||
#ifdef FEAT_MBYTE
|
||||
if (has_mbyte)
|
||||
new_slen += (*mb_char2bytes)(key_name[1], string + new_slen);
|
||||
else
|
||||
#endif
|
||||
string[new_slen++] = key_name[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
string[new_slen++] = K_SPECIAL;
|
||||
|
||||
@@ -25,7 +25,8 @@ SCRIPTS = test1.out test3.out test4.out test5.out test6.out \
|
||||
test43.out test44.out test45.out test46.out test47.out \
|
||||
test48.out test51.out test53.out test54.out test55.out \
|
||||
test56.out test57.out test58.out test59.out test60.out \
|
||||
test61.out test62.out test63.out test64.out test65.out
|
||||
test61.out test62.out test63.out test64.out test65.out \
|
||||
test66.out
|
||||
|
||||
.SUFFIXES: .in .out
|
||||
|
||||
@@ -110,3 +111,4 @@ test62.out: test62.in
|
||||
test63.out: test63.in
|
||||
test64.out: test64.in
|
||||
test65.out: test65.in
|
||||
test66.out: test66.in
|
||||
|
||||
@@ -26,7 +26,7 @@ SCRIPTS = test3.out test4.out test5.out test6.out test7.out \
|
||||
test15.out test17.out test18.out test21.out test26.out \
|
||||
test30.out test31.out test32.out test33.out test34.out \
|
||||
test37.out test38.out test39.out test40.out test41.out \
|
||||
test42.out test52.out test65.out
|
||||
test42.out test52.out test65.out test66.out
|
||||
|
||||
SCRIPTS32 = test50.out
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ SCRIPTS = test3.out test4.out test5.out test6.out test7.out \
|
||||
test15.out test17.out test18.out test21.out test26.out \
|
||||
test30.out test31.out test32.out test33.out test34.out \
|
||||
test37.out test38.out test39.out test40.out test41.out \
|
||||
test42.out test52.out test65.out
|
||||
test42.out test52.out test65.out test66.out
|
||||
|
||||
SCRIPTS32 = test50.out
|
||||
|
||||
|
||||
@@ -25,7 +25,8 @@ SCRIPTS = test1.out test3.out test4.out test5.out test6.out \
|
||||
test43.out test44.out test45.out test46.out test47.out \
|
||||
test48.out test51.out test53.out test54.out test55.out \
|
||||
test56.out test57.out test58.out test59.out test60.out \
|
||||
test61.out test62.out test63.out test64.out test65.out
|
||||
test61.out test62.out test63.out test64.out test65.out \
|
||||
test66.out
|
||||
|
||||
.SUFFIXES: .in .out
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# Authors: Zoltan Arpadffy, <arpadffy@polarhome.com>
|
||||
# Sandor Kopanyi, <sandor.kopanyi@mailbox.hu>
|
||||
#
|
||||
# Last change: 2008 Aug 19
|
||||
# Last change: 2009 Mar 05
|
||||
#
|
||||
# This has been tested on VMS 6.2 to 8.3 on DEC Alpha, VAX and IA64.
|
||||
# Edit the lines in the Configuration section below to select.
|
||||
@@ -68,7 +68,8 @@ SCRIPT = test1.out test2.out test3.out test4.out test5.out \
|
||||
test43.out test44.out test45.out test46.out \
|
||||
test48.out test51.out test53.out test54.out test55.out \
|
||||
test56.out test57.out test60.out \
|
||||
test61.out test62.out test63.out test64.out test65.out
|
||||
test61.out test62.out test63.out test64.out test65.out \
|
||||
test66.out
|
||||
|
||||
.IFDEF WANT_GUI
|
||||
SCRIPT_GUI = test16.out
|
||||
|
||||
@@ -20,7 +20,7 @@ SCRIPTS = test1.out test2.out test3.out test4.out test5.out test6.out \
|
||||
test48.out test49.out test51.out test52.out test53.out \
|
||||
test54.out test55.out test56.out test57.out test58.out \
|
||||
test59.out test60.out test61.out test62.out test63.out \
|
||||
test64.out test65.out
|
||||
test64.out test65.out test66.out
|
||||
|
||||
SCRIPTS_GUI = test16.out
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
Test for visual block shift and tab characters.
|
||||
|
||||
STARTTEST
|
||||
:so small.vim
|
||||
/^abcdefgh
|
||||
4jI j<<11|D
|
||||
7|a
|
||||
7|a
|
||||
7|a 4k13|4j<
|
||||
:$-4,$w! test.out
|
||||
:$-4,$s/\s\+//g
|
||||
4kI j<<
|
||||
7|a
|
||||
7|a
|
||||
7|a 4k13|4j3<
|
||||
:$-4,$w >> test.out
|
||||
:qa!
|
||||
ENDTEST
|
||||
|
||||
abcdefghijklmnopqrstuvwxyz
|
||||
abcdefghijklmnopqrstuvwxyz
|
||||
abcdefghijklmnopqrstuvwxyz
|
||||
abcdefghijklmnopqrstuvwxyz
|
||||
abcdefghijklmnopqrstuvwxyz
|
||||
@@ -0,0 +1,10 @@
|
||||
abcdefghijklmnopqrstuvwxyz
|
||||
abcdefghij
|
||||
abc defghijklmnopqrstuvwxyz
|
||||
abc defghijklmnopqrstuvwxyz
|
||||
abc defghijklmnopqrstuvwxyz
|
||||
abcdefghijklmnopqrstuvwxyz
|
||||
abcdefghij
|
||||
abc defghijklmnopqrstuvwxyz
|
||||
abc defghijklmnopqrstuvwxyz
|
||||
abc defghijklmnopqrstuvwxyz
|
||||
+146
@@ -691,6 +691,152 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
148,
|
||||
/**/
|
||||
147,
|
||||
/**/
|
||||
146,
|
||||
/**/
|
||||
145,
|
||||
/**/
|
||||
144,
|
||||
/**/
|
||||
143,
|
||||
/**/
|
||||
142,
|
||||
/**/
|
||||
141,
|
||||
/**/
|
||||
140,
|
||||
/**/
|
||||
139,
|
||||
/**/
|
||||
138,
|
||||
/**/
|
||||
137,
|
||||
/**/
|
||||
136,
|
||||
/**/
|
||||
135,
|
||||
/**/
|
||||
134,
|
||||
/**/
|
||||
133,
|
||||
/**/
|
||||
132,
|
||||
/**/
|
||||
131,
|
||||
/**/
|
||||
130,
|
||||
/**/
|
||||
129,
|
||||
/**/
|
||||
128,
|
||||
/**/
|
||||
127,
|
||||
/**/
|
||||
126,
|
||||
/**/
|
||||
125,
|
||||
/**/
|
||||
124,
|
||||
/**/
|
||||
123,
|
||||
/**/
|
||||
122,
|
||||
/**/
|
||||
121,
|
||||
/**/
|
||||
120,
|
||||
/**/
|
||||
119,
|
||||
/**/
|
||||
118,
|
||||
/**/
|
||||
117,
|
||||
/**/
|
||||
116,
|
||||
/**/
|
||||
115,
|
||||
/**/
|
||||
114,
|
||||
/**/
|
||||
113,
|
||||
/**/
|
||||
112,
|
||||
/**/
|
||||
111,
|
||||
/**/
|
||||
110,
|
||||
/**/
|
||||
109,
|
||||
/**/
|
||||
108,
|
||||
/**/
|
||||
107,
|
||||
/**/
|
||||
106,
|
||||
/**/
|
||||
105,
|
||||
/**/
|
||||
104,
|
||||
/**/
|
||||
103,
|
||||
/**/
|
||||
102,
|
||||
/**/
|
||||
101,
|
||||
/**/
|
||||
100,
|
||||
/**/
|
||||
99,
|
||||
/**/
|
||||
98,
|
||||
/**/
|
||||
97,
|
||||
/**/
|
||||
96,
|
||||
/**/
|
||||
95,
|
||||
/**/
|
||||
94,
|
||||
/**/
|
||||
93,
|
||||
/**/
|
||||
92,
|
||||
/**/
|
||||
91,
|
||||
/**/
|
||||
90,
|
||||
/**/
|
||||
89,
|
||||
/**/
|
||||
88,
|
||||
/**/
|
||||
87,
|
||||
/**/
|
||||
86,
|
||||
/**/
|
||||
85,
|
||||
/**/
|
||||
84,
|
||||
/**/
|
||||
83,
|
||||
/**/
|
||||
82,
|
||||
/**/
|
||||
81,
|
||||
/**/
|
||||
80,
|
||||
/**/
|
||||
79,
|
||||
/**/
|
||||
78,
|
||||
/**/
|
||||
77,
|
||||
/**/
|
||||
76,
|
||||
/**/
|
||||
75,
|
||||
/**/
|
||||
|
||||
@@ -710,7 +710,8 @@ extern char *(*dyn_libintl_textdomain)(const char *domainname);
|
||||
#define EXPAND_USER_DEFINED 30
|
||||
#define EXPAND_USER_LIST 31
|
||||
#define EXPAND_SHELLCMD 32
|
||||
#define EXPAND_MACACTION 33
|
||||
#define EXPAND_CSCOPE 33
|
||||
#define EXPAND_MACACTION 34
|
||||
|
||||
/* Values for exmode_active (0 is no exmode) */
|
||||
#define EXMODE_NORMAL 1
|
||||
@@ -1060,6 +1061,7 @@ extern char *(*dyn_libintl_textdomain)(const char *domainname);
|
||||
#define WSP_HELP 16 /* creating the help window */
|
||||
#define WSP_BELOW 32 /* put new window below/right */
|
||||
#define WSP_ABOVE 64 /* put new window above/left */
|
||||
#define WSP_NEWLOC 128 /* don't copy location list */
|
||||
|
||||
/*
|
||||
* arguments for gui_set_shellsize()
|
||||
|
||||
+16
-7
@@ -12,7 +12,7 @@
|
||||
static int path_is_url __ARGS((char_u *p));
|
||||
#if defined(FEAT_WINDOWS) || defined(PROTO)
|
||||
static int win_split_ins __ARGS((int size, int flags, win_T *newwin, int dir));
|
||||
static void win_init __ARGS((win_T *newp, win_T *oldp));
|
||||
static void win_init __ARGS((win_T *newp, win_T *oldp, int flags));
|
||||
static void frame_comp_pos __ARGS((frame_T *topfrp, int *row, int *col));
|
||||
static void frame_setheight __ARGS((frame_T *curfrp, int height));
|
||||
#ifdef FEAT_VERTSPLIT
|
||||
@@ -594,9 +594,7 @@ wingotofile:
|
||||
++allow_keys; /* no mapping for xchar, but allow key codes */
|
||||
if (xchar == NUL)
|
||||
xchar = plain_vgetc();
|
||||
#ifdef FEAT_LANGMAP
|
||||
LANGMAP_ADJUST(xchar, TRUE);
|
||||
#endif
|
||||
--no_mapping;
|
||||
--allow_keys;
|
||||
#ifdef FEAT_CMDL_INFO
|
||||
@@ -913,7 +911,7 @@ win_split_ins(size, flags, newwin, dir)
|
||||
return FAIL;
|
||||
|
||||
/* make the contents of the new window the same as the current one */
|
||||
win_init(wp, curwin);
|
||||
win_init(wp, curwin, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1162,11 +1160,15 @@ win_split_ins(size, flags, newwin, dir)
|
||||
* Initialize window "newp" from window "oldp".
|
||||
* Used when splitting a window and when creating a new tab page.
|
||||
* The windows will both edit the same buffer.
|
||||
* WSP_NEWLOC may be specified in flags to prevent the location list from
|
||||
* being copied.
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
static void
|
||||
win_init(newp, oldp)
|
||||
win_init(newp, oldp, flags)
|
||||
win_T *newp;
|
||||
win_T *oldp;
|
||||
int flags;
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -1191,7 +1193,14 @@ win_init(newp, oldp)
|
||||
copy_jumplist(oldp, newp);
|
||||
#endif
|
||||
#ifdef FEAT_QUICKFIX
|
||||
copy_loclist(oldp, newp);
|
||||
if (flags & WSP_NEWLOC)
|
||||
{
|
||||
/* Don't copy the location list. */
|
||||
newp->w_llist = NULL;
|
||||
newp->w_llist_ref = NULL;
|
||||
}
|
||||
else
|
||||
copy_loclist(oldp, newp);
|
||||
#endif
|
||||
if (oldp->w_localdir != NULL)
|
||||
newp->w_localdir = vim_strsave(oldp->w_localdir);
|
||||
@@ -3221,7 +3230,7 @@ win_alloc_firstwin(oldwin)
|
||||
else
|
||||
{
|
||||
/* First window in new tab page, initialize it from "oldwin". */
|
||||
win_init(curwin, oldwin);
|
||||
win_init(curwin, oldwin, 0);
|
||||
|
||||
# ifdef FEAT_SCROLLBIND
|
||||
/* We don't want scroll-binding in the first window. */
|
||||
|
||||
Reference in New Issue
Block a user