a while ago Niklas Lindström suggested using the Scripting Bridge to
add custom gui windows to a running gvim ( http://groups.google.com/group/vim_mac/msg/039cf197bad56963
).
I played around with this for a short while, and it kinda works. Save
this program to a file, open it in vim and do `:pyfile %`. This will
open a window that contains a list of all the buffers you have open in
the vim you issued this command in, in a NSTableView (the default
cocoa table class).
<code>
from AppKit import *
import vim
class DataSource(NSObject):
def numberOfRowsInTableView_(self, tableView):
return len(vim.buffers)
def tableView_objectValueForTableColumn_row_(self, tableView,
tableColumn, row):
return vim.buffers[row].name
# Not required in vim-cocoa which already has a shared app in the vim
process
NSApplication.sharedApplication()
w = NSWindow.alloc().initWithContentRect_styleMask_backing_defer_(
NSMakeRect(0, 0, 400, 200), NSTitledWindowMask |
NSClosableWindowMask
| NSMiniaturizableWindowMask | NSResizableWindowMask,
NSBackingStoreBuffered, True)
t = NSTableView.alloc().initWithFrame_(NSMakeRect(10, 10, 300, 180))
ds = DataSource.alloc().init()
t.setDataSource_(ds)
c = NSTableColumn.alloc().initWithIdentifier_("Buffers")
c.setWidth_(300)
t.addTableColumn_(c)
t.sizeLastColumnToFit()
t.setHidden_(False)
w.contentView().addSubview_(t)
w.orderFront_(None)
</code>
However, there are a few (serious) problems:
1. This requires the python objective c bridge. This is include in the
python2.5 that's included with Leopard, but you probably have to
install it somehow manually on Tiger.
2. The release builds of MacVim link with python2.3, so if you want to
use MacVim with this you need to compile it yourself (and it still
won't work, see below)
3. The vim this is executing in needs to use some basic cocoa stuff
(like an autorelease pool and I guess most importantly an NSRunLoop).
This rules out carbon vim altogether, and sadly it rules out MacVim as
well (because MacVim uses Cocoa only in the gui process, but python is
executed in the core vim process). This leaves vim-cocoa. It actually
works just fine in vim-cocoa, but the binary release doesn't include
python support, so you have to compile it yourself (it's easy, there's
excellent documentation at http://code.google.com/p/vim-cocoa/wiki/BuildInstructions
).
4. Doing `:pyfile %` more than once crashes.
If you try this in (a self-compiled) MacVim, the window will show up,
but it won't do anything because it belongs to the vim core thread
which has no cocoa event loop. The `NSApplication.sharedApplication()`
line above creates a cocoa application in the vim core process (you
even get another vim icon in the dock for that), but since there's no
event loop the window shows up and does nothing.
In conclusion:
* This is very cool
* Just imagine what kind of plugins you could do with this
* It doesn't work in MacVim and I see no way to fix this
* Well, perhaps except telling the gui in the vim core process to not
show a dock icon and to put a run loop in there -- but it's not
trivial to do this I guess
* But it might still be worthwhile to try
* Then again, this approach would not allow adding views to the vim
window (since it belongs to a different process), which would be kinda
cool as well
Nico
I don't understand myself exactly what it is you are doing, but let me
clarify some of the MacVim related points.
MacVim sets up autorelease pools (Cocoa basically cannot run without
one) in main.c so this is not the problem. Also, each Vim process
does have a run loop, search inside MMBackend.m. A run loop is needed
for distributed objects.
>
> 4. Doing `:pyfile %` more than once crashes.
>
> If you try this in (a self-compiled) MacVim, the window will show up,
> but it won't do anything because it belongs to the vim core thread
> which has no cocoa event loop. The `NSApplication.sharedApplication()`
> line above creates a cocoa application in the vim core process (you
> even get another vim icon in the dock for that), but since there's no
> event loop the window shows up and does nothing.
Here is something that does not happen in each Vim process. No
NSApplication object is ever instantiated and hence [NSApp run] isn't
called. This is where the AppKit magic happens...stuff gets
initialized etc. Without [NSApp run] you only get access to
Foundation functionality. I guess it is feasible to start up NSApp
inside a Vim process, but you'll have to make some hacks to get out of
it ([NSApp run] never exits)...check out vim-cocoa how this is done.
Also, once NSApp is set up you'll probably have to update it every now
and again by calling [NSApp run] and breaking out. It might just work
to directly operate on the run loop (the way it is done now), but I'm
not sure.
> In conclusion:
>
> * This is very cool
> * Just imagine what kind of plugins you could do with this
> * It doesn't work in MacVim and I see no way to fix this
> * Well, perhaps except telling the gui in the vim core process to not
> show a dock icon and to put a run loop in there -- but it's not
> trivial to do this I guess
> * But it might still be worthwhile to try
> * Then again, this approach would not allow adding views to the vim
> window (since it belongs to a different process), which would be kinda
> cool as well
I don't have any idea either. Mostly because I don't understand what
you are doing (due to my ineptitude) :-)
/Björn
Well, it's a vim-python script (`:h python`) that opens a window (an
NSWindow, not a text window) inside the vim process, so it has access
to all the vim stuff. You could create a window with a "New Line"
button that inserts a new line in the current vim buffer (or even
something useful), from within a vim script (for example, a plugin).
> but let me clarify some of the MacVim related points.
Thanks for the clarifications. I'll take a look at how vim-cocoa
manages to call [NSApp run].
Nico
On Dec 3, 2007 2:24 AM, Nico Weber <nicola...@gmx.de> wrote:
> Thanks for the clarifications. I'll take a look at how vim-cocoa
> manages to call [NSApp run].
vim-cocoa does event loop in following ways:
1. Most of the time (in gui_mch_wait_for_chars()), it just fetches a
new event with [NSApp nextEventMatchingMask:untilDate:inMode:dequeue:]
and dispatch it with [NSApp sendEvent:].
2. Like Björn said, we have to execute [NSApp run] at least once to do
some magical initialization stuff. So when gui_mch_wait_for_chars()
gets called the first time, I set up a one-shot timer called
initializeApplicationTimer which will be fired after 0.1 second, then
call [NSApp run], let the timer to stop the NSApp event loop with
[NSApp stop: self].
3. Some modal dialogs require similar steps like (2), but we can call
[NSApp stop: self] in events like -alertDidEnd:returnCode:contextInfo:,
so no extra timer needed.
HTH.
- Jiang
For the record:
Another way that works (I have tried it) is to define a user event,
then override [NSApplication sendEvent] (in a subclass) to stop the
run loop when this user event is received (by calling [NSApp stop]).
Finally, before calling [NSApp run] the first time you post your user
event, then call [NSApp run] and it will do its initialization and
immediately return. :-)
/Björn
> Anyway, when adding the GUI to MacVim as a plugin, there is no way to
> get access to the Vim GUI. Basically, I wanted to pop up my file
> selector as a modal window on top of the main window, but since
> NSApp.keyWindow returns nil (well, None in PyObjC), the best I can do
> is essentially create a separate app, complete with startup time and
> Dock icon.
>
> Would it be possible to run Python commands (:py) in the GUI, rather
> than the Vim process? I don't know enough about Vim internals to know
> how much this would complicate eg Python's Vim support ("import vim").
As Nico stated in his previous mail, MacVim GUI is separated with the
vim process, but The functionality you described seemed have nothing to
do with the "core" vim part, could you elaborate on what kind of
information you want to get from vim?
Of course it's possible to have embedded Python support in MacVim GUI,
you can just add the Python.framework into MacVim.xcodeproj, then find a
proper place to do something like PySimpleString (you can do more
complicated stuff of course), but this Python embedding will have nothing
to do with the vim process, so it won't be that easy to fetch some useful
information from that process.
HTH.
- Jiang