1 This README contains an overview of the MacVim source code and a very short
2 description on how to build the application.
4 The information in here is not meant to be exhaustive. A lot more information
5 can be found in the source code comments.
10 MacVim.app consists of two executables: MacVim and Vim. MacVim is a Cocoa app
11 which does all the window management including drawing and receiving input.
12 Vim is the actual editor which receives input from MacVim and sends output
13 back when there is something to draw.
15 As far as the source code files goes, MacVim.[m|h] contains code shared
16 between MacVim and Vim, gui_macvim.m and MMBackend.[m|h] belongs to Vim,
17 everything else belongs to MacVim. (The source code is all Objective-C which
18 is very easy to pick up if you know C and some object oriented programming.)
20 Each editor window in MacVim runs its own Vim process (but there is always
21 only one MacVim process). Communication between MacVim and a Vim process is
22 done using Distributed Objects (DO). Each Vim process is represented by a
23 backend object (MMBackend) and it communicates with a frontend object in the
24 Vim process (MMVimController). The interface between the backend and frontend
25 is defined in MacVim.h.
27 The frontend sends input to the backend by calling
28 -[MMBackend processInput:data:]. The backend queues output on a command queue
29 and sends it to the frontend at opportune times by calling
30 -[MMVimController processCommandQueue:]. These are both asynchronous calls so
31 MacVim can keep drawing and receiving input while Vim is working away, thus
32 always keeping the user interface responsive.
34 The state of each editor window is kept entirely in the Vim process. MacVim
35 should remain "ignorant" in the sense that it knows nothing of the actual
36 state of a Vim process. Typically this is not a problem, but sometimes MacVim
37 must change state without going via Vim, and sometimes MacVim needs immediate
38 access to the state from Vim. The former happens e.g. when the user drags to
39 resize a window (MacVim changes the window dimensions immediately without
40 asking Vim first), the second can happen when some option variable affects the
41 way something is presented visually (e.g. MacVim needs immediate access to the
42 'mousehide' option so that it can hide the mouse cursor when input is
43 received). State information that may be required in this way can be "pushed"
44 to MacVim inside -[MMBackend queueVimStateMessage].
49 Hooks from within Vim are implmented in gui_macvim.m, the name of such
50 functions usually start with "gui_mch_" and they should simply put a message
51 on the output queue, by calling queueMessage:properties: on the singleton
52 MMBackend object [MMBackend sharedInstance] (see e.g. gui_mch_destroy_menu()).
53 The output queue is flushed when requested (in -[MMBackend flushQueue]) or
54 before Vim takes a nap whilst waiting for new input (in
55 -[MMBackend waitForInput]).
57 Note that each Vim process has its own run loop (it is required for DO) and
58 since Vim is in charge of its thread it needs to "update" the run loop
59 manually. This can happen in -[MMBackend update], which returns immediately
60 if nothing is pending on the run loop, or in -[MMBackend waitForInput], which
61 can possibly block until input appears on the run loop. In any case, if Vim
62 for some reason fails to update the run loop then incoming DO calls will not
63 be processed and for this reason it is best to avoid making synchronous DO
64 calls from MacVim. (If synchronous calls must be made then it is important to
65 set proper timeouts so that MacVim doesn't "hang", see
66 -[MMVimConroller sendMessageNow:::] to see how this can be done.)
71 The main nib of MacVim.app is MainMenu.nib which contains the default menu and
72 an instance of MMAppController, which is connected as the delegate of
73 NSApplication. That means, when MacVim starts it will load this nib file and
74 automatically create an instance of the MMAppController singleton.
76 A new editor window is opened by calling
77 -[MMAppController launchVimProcessWithArguments:]. This functions starts a
78 new Vim process (by executing the Vim binary). The Vim process lets MacVim
79 know when it has launched by calling -[MMAppController connectBackend:pid:]
80 and MacVim responds to this message by creating a new frontend object
81 (MMVimController) and returns a proxy to this object back to the Vim process.
82 From this point onward the Vim process communicates directly with the
85 The MMVimController represents the frontend of a Vim process inside MacVim.
86 It coordinates all communication with the Vim process and delegates output
87 that affects visual presentation to a MMWindowController object. Read the
88 Cocoa documentation on the responsibilities of a window controller.
90 Input (keyboard & mouse) handling and drawing is handled by a helper object
91 (MMTextViewHelper) to the current text view (MMTextView, MMAtsuiTextView).
94 Distributed Object dangers:
96 Distributed Object messages are handled whenever the run loop is updated.
97 Since the run loop can be updated at unpredictable times some care has to be
98 taken when implementing DO messages. Some unexpected examples of when the run
101 1. When a synchronous DO message is sent. The run loop goes into a loop
102 waiting for a return to the synchronous message; During this wait another DO
105 2. When a modal loop is entered. For example, when a user presses a Cmd-key
106 the menu flashes briefly. During this "flash" a modal loop is entered.
108 Item 1 can cause a problem if MacVim sends a synchronous message and before a
109 reply reacheds MacVim another message is received. From the source code it
110 looks like the synchronous message blocks but in fact the other message is
111 executed during this "block". If the other message changes state radically
112 something may go wrong after the synchronous DO message returns.
114 Item 2 can cause similar problems but it may happen deep inside a Cocoa call
115 which may be even more puzzling.
117 One way to alleviate these problems is to ensure a DO message isn't entered
118 twice by setting a boolean at the beginning of the message and clearing it
119 afterwards. If the boolean is already set when entering the call must somehow
120 be delayed. See -[MMVimController processCommandQueue:] for a concrete
123 Another danger is that we must take care when releasing objects that Cocoa may
124 be using. See -[MMVimController connectionDidDie:] how MacVim releases
125 MMVimControllers when the Vim process they control exits.
128 Source code file organisation:
130 Here is an incomplete list of source code files with a short explanation of
133 MMAppController.* Everything related to running the application
134 MMBackend.* Object representing a Vim process in backend
135 MMTextView.* Handles input and drawing
136 MMVimController.* Object representing a Vim Process in frontend
137 MMVimView.* Cocoa view object
138 MMWindowController.* Coordinates visual presentation
139 MacVim.* Code shared between MacVim and Vim
140 gui_macvim.m Hooks from Vim
145 You will need to install the Xcode tools before building the source code.
146 Nothing else needs to be installed in order to build MacVim.
148 Steps to build MacVim.app (the text before the '$' shows the folder you should
149 be in when executing these commands):
152 src/$ ./configure --enable-gui=macvim
154 2. Build Vim executable
157 3. Build MacVim.app application bundle
158 src/MacVim/$ xcodebuild
160 The application bundle can be found inside "src/MacVim/build/Release".
163 Bjorn Winckler <bjorn.winckler@gmail.com>