Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
..
Failed to load latest commit information.
English.lproj Update copyright year
MacVim.xcodeproj Snapshot 73
PSMTabBarControl Fix background color of active tab for Yosemite
Sparkle.framework Sparkle support for automatic updates
Toolbar Change a few toolbar icons
icons Handle spaces in output directories
Actions.plist Deprecate "Force New Window" menu
Advanced.png Remove +x flag on Advanced.png
Colors.plist Colors.plist autogenerated from "showrgb" command
Credits.rtf Update credits
DBPrefsWindowController.h MAC_OS_X_VERSION_10_6 not defined on pre-10.6
DBPrefsWindowController.m Fix static analyzer warning in DBPrefs
General.png Preference panel update, input manager installer
Info.plist Snapshot 73
KeyBinding.plist Alt+Space mappings in Keyboard Layouts now work
MMAppController.h Change default font to Menlo
MMAppController.m Don't double-encode URLs before parsing them
MMApplication.h Revert "Modifier key sends Esc" related commits
MMApplication.m Use availability macros correctly
MMAtsuiTextView.h Listen to InputSourceChanged notification
MMAtsuiTextView.m Listen to InputSourceChanged notification
MMBackend.h Use "full-screen" and [Ff]ullScreen consistently
MMBackend.m Fix getfontname()
MMCoreTextView+ToolTip.m Fix problem when compiling without Core Text
MMCoreTextView.h Stop using 10.9 deprecated CGContext function
MMCoreTextView.m Stop using 10.9 deprecated CGContext function
MMFindReplaceController.h Add Find & Replace dialog box
MMFindReplaceController.m Add Find & Replace dialog box
MMFullScreenWindow.h Rename MMFullscreenWindow -> MMFullScreenWindow
MMFullScreenWindow.m Rename MMFullscreenWindow -> MMFullScreenWindow
MMPreferenceController.h Remove 'Edit in ODBEditor'
MMPreferenceController.m Remove 'Edit in ODBEditor'
MMTextStorage.h Fix wide character support for 64 bit
MMTextStorage.m Fix clang compiler and static analyzer warnings
MMTextView.h Listen to InputSourceChanged notification
MMTextView.m Fix clang compiler and static analyzer warnings
MMTextViewHelper.h Fix window dimension autosave regression
MMTextViewHelper.m Fix window restore on enter full-screen failure
MMTypesetter.h New text drawing model, better unicode support, 'gfw' support, etc.
MMTypesetter.m Prepare for 64 bit
MMVimController.h Fix visibility of toolbar in full screen
MMVimController.m Only select directories in browsedir()
MMVimView.h Avoid window flashing white when opened
MMVimView.m Fix clang compiler and static analyzer warnings
MMWindow.h Add user default for native/custom full screen
MMWindow.m Avoid compilation warning on OS X 10.4 - 10.6
MMWindowController.h Change full-screen maximization heuristic
MMWindowController.m Respond to backing properties changes
MacVim.h Respond to backing properties changes
MacVim.m Respond to backing properties changes
MacVim_Prefix.pch Moved MacVim project to src/MacVim and removed runtime folder
Miscellaneous.h Fix window dimension autosave regression
Miscellaneous.m Add user default for native/custom full screen
README Add note on document icon generation to README
SystemColors.plist Moved MacVim project to src/MacVim and removed runtime folder
gui_macvim.m Avoid directly calling objc runtime functions in C
gvimrc Use “noremap” for all other mappings too
ibeam.png Higher constrast mouse cursor in insert mode
main.m Moved MacVim project to src/MacVim and removed runtime folder
mvim Support "mvim" script symlinks to [m|g]ex, rmvim
vimrc Disable localized menus in system vimrc

README

This README contains an overview of the MacVim source code and a very short
description on how to build the application.

The information in here is not meant to be exhaustive.  A lot more information
can be found in the source code comments.


Source code overview:

MacVim.app consists of two executables: MacVim and Vim.  MacVim is a Cocoa app
which does all the window management including drawing and receiving input.
Vim is the actual editor which receives input from MacVim and sends output
back when there is something to draw.

As far as the source code files goes, MacVim.[m|h] contains code shared
between MacVim and Vim, gui_macvim.m and MMBackend.[m|h] belongs to Vim,
everything else belongs to MacVim.  (The source code is all Objective-C which
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 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
-[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
state of a Vim process.  Typically this is not a problem, but sometimes MacVim
must change state without going via Vim, and sometimes MacVim needs immediate
access to the state from Vim.  The former happens e.g. when the user drags to
resize a window (MacVim changes the window dimensions immediately without
asking Vim first), the second can happen when some option variable affects the
way something is presented visually (e.g. MacVim needs immediate access to the
'mousehide' option so that it can hide the mouse cursor when input is
received).  State information that may be required in this way can be "pushed"
to MacVim inside -[MMBackend queueVimStateMessage].


Vim:

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()).
The output queue is flushed when requested (in -[MMBackend flushQueue]) or
before Vim takes a nap whilst waiting for new input (in
-[MMBackend waitForInput]).

Note that each Vim process has its own run loop (it is required for DO) and
since Vim is in charge of its thread it needs to "update" the run loop
manually.  This can happen in -[MMBackend update], which returns immediately
if nothing is pending on the run loop, or in -[MMBackend waitForInput], which
can possibly block until input appears on the run loop.  In any case, if Vim
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
-[MMVimController sendMessageNow:::] to see how this can be done.)


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.  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 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
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, MMCoreTextView, ...).


Distributed Object dangers:

Distributed Object messages are handled whenever the run loop is updated.
Since the run loop can be updated at unpredictable times some care has to be
taken when implementing DO messages.  Some unexpected examples of when the run
loop is updated:

1. When a synchronous DO message is sent.  The run loop goes into a loop
waiting for a return to the synchronous message;  During this wait another DO
message may arrive.

2. When a modal loop is entered.  For example, when a user presses a Cmd-key
the menu flashes briefly.  During this "flash" a modal loop is entered.

3. From a secondary thread.

Item 1 can cause a problem if MacVim sends a synchronous message and before a
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.

Item 2 can cause similar problems but it may happen deep inside a Cocoa call
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 processInput:forIdentifier: and processInputQueues: inside
MMAppController for a concrete example.

Item 3 may seem harmless since MacVim does not spawn any secondary threads.
However, when an "open file" dialog is displayed, Cocoa spawns several new
threads.  From then onwards, it seems that DO messages may arrive in a thread
which isn't the "main thread" (or is it only notifications such as
NSConnectionDidDieNotification that may arrive in secondary threads?).  The
message
-[NSObject performSelector:onThread:withObject:waitUntilDone:modes:]is often
used to work around this problem (see e.g. -[MMVimController scheduleClose]).

Another danger is that we must take care when releasing objects that Cocoa may
be using.  See -[MMVimController scheduleClose] how MacVim releases
MMVimControllers when the Vim process they control exits.


Source code file organisation:

Here is an incomplete list of source code files with a short explanation of
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
    MMVimView.*             Cocoa view object
    MMWindowController.*    Coordinates visual presentation
    MacVim.*                Code shared between MacVim and Vim
    Miscellaneous.*         Miscellaneous code only used inside MacVim
    gui_macvim.m            Hooks from Vim


Building:

You will need to install the Xcode tools before building the source code.
Nothing else needs to be installed in order to build MacVim.

Steps to build MacVim.app (the text before the '$' shows the folder you should
be in when executing these commands):

1. Configure Vim (call "./configure --help" to see a list of flags)
    src/$ ./configure

2. Generate document icons (OPTIONAL)
    src/MacVim/icons$ make getenvy
    src/MacVim/icons$ make all

3. Build
    src/$ make

The application bundle can be found inside "src/MacVim/build/Release".

If step 2 is skipped a generic document icon will be used for all file types.
It is also possible to download the document icons if this step fails.


Bjorn Winckler <bjorn.winckler@gmail.com>
March 21, 2011
Something went wrong with that request. Please try again.