Loading ...
Sorry, an error occurred while loading the content.
 

Vim plugins with a Cocoa gui

Expand Messages
  • Nico Weber
    Hi all, a while ago Niklas Lindström suggested using the Scripting Bridge to add custom gui windows to a running gvim (
    Message 1 of 10 , Dec 2, 2007
      Hi all,

      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
      --~--~---------~--~----~------------~-------~--~----~
      You received this message from the "vim_mac" maillist.
      For more information, visit http://www.vim.org/maillist.php
      -~----------~----~----~----~------~----~------~--~---
    • björn
      Hi 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
      Message 2 of 10 , Dec 2, 2007
        Hi Nico,

        I don't understand myself exactly what it is you are doing, but let me
        clarify some of the MacVim related points.

        On 02/12/2007, Nico Weber <nicolasweber@...> wrote:
        >
        > Hi all,
        >
        > 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
        > ).

        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

        --~--~---------~--~----~------------~-------~--~----~
        You received this message from the "vim_mac" maillist.
        For more information, visit http://www.vim.org/maillist.php
        -~----------~----~----~----~------~----~------~--~---
      • Nico Weber
        ... 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
        Message 3 of 10 , Dec 2, 2007
          > I don't understand myself exactly what it is you are doing

          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

          --~--~---------~--~----~------------~-------~--~----~
          You received this message from the "vim_mac" maillist.
          For more information, visit http://www.vim.org/maillist.php
          -~----------~----~----~----~------~----~------~--~---
        • Jjgod Jiang
          Hi, ... 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
          Message 4 of 10 , Dec 2, 2007
            Hi,

            On Dec 3, 2007 2:24 AM, Nico Weber <nicolasweber@...> 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

            --~--~---------~--~----~------------~-------~--~----~
            You received this message from the "vim_mac" maillist.
            For more information, visit http://www.vim.org/maillist.php
            -~----------~----~----~----~------~----~------~--~---
          • björn
            ... 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
            Message 5 of 10 , Dec 2, 2007
              On 02/12/2007, Jjgod Jiang <gzjjgod@...> wrote:
              >
              > On Dec 3, 2007 2:24 AM, Nico Weber <nicolasweber@...> 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:
              >
              > 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].

              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

              --~--~---------~--~----~------------~-------~--~----~
              You received this message from the "vim_mac" maillist.
              For more information, visit http://www.vim.org/maillist.php
              -~----------~----~----~----~------~----~------~--~---
            • Panos
              This is pretty exciting mate. Maybe one day we ll get to have the cocoa frontend for Project.vim :) ... --~--~---------~--~----~------------~-------~--~----~
              Message 6 of 10 , Dec 3, 2007
                This is pretty exciting mate.

                Maybe one day we'll get to have the cocoa frontend for Project.vim :)

                On Dec 3, 12:20 am, "björn" <bjorn.winck...@...> wrote:
                > On 02/12/2007, Jjgod Jiang <gzjj...@...> wrote:
                >
                >
                >
                > > On Dec 3, 2007 2:24 AM, Nico Weber <nicolaswe...@...> 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:
                >
                > > 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].
                >
                > 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
                --~--~---------~--~----~------------~-------~--~----~
                You received this message from the "vim_mac" maillist.
                For more information, visit http://www.vim.org/maillist.php
                -~----------~----~----~----~------~----~------~--~---
              • Nicholas
                ... Hi all, I was doing the same sort of thing recently and encountered the same problems. I really like TextMate s fuzzy-matching file selection (using
                Message 7 of 10 , Dec 30, 2007
                  On Dec 3, 4:51 am, Nico Weber <nicolaswe...@...> wrote:
                  > Hi all,
                  >
                  > 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.

                  Hi all,

                  I was doing the same sort of thing recently and encountered the same
                  problems.

                  I really like TextMate's fuzzy-matching file selection (using cmt-T),
                  so I recreated its gui using Python and PyObjC. If you're not familiar
                  with it, pressing cmt-T brings up a window containing a text box and a
                  list of all files in the cwd and below. Typing into the text box
                  narrows the list of filenames. It has a couple of other niceties (such
                  as fuzzy matching).

                  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").

                  --~--~---------~--~----~------------~-------~--~----~
                  You received this message from the "vim_mac" maillist.
                  For more information, visit http://www.vim.org/maillist.php
                  -~----------~----~----~----~------~----~------~--~---
                • Panos
                  Maybe it would require macvim exposing it s gui, so `import vim`, for the buffer stuff etc, and `import macvim`, to get to the gui. ...
                  Message 8 of 10 , Dec 31, 2007
                    Maybe it would require macvim exposing it's gui, so `import vim`, for
                    the buffer stuff etc, and `import macvim`, to get to the gui.

                    On Dec 31, 8:32 am, Nicholas <nicholas.fitzroy.d...@...> wrote:
                    > On Dec 3, 4:51 am, Nico Weber <nicolaswe...@...> wrote:
                    >
                    > > Hi all,
                    >
                    > > 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.
                    >
                    > Hi all,
                    >
                    > I was doing the same sort of thing recently and encountered the same
                    > problems.
                    >
                    > I really like TextMate's fuzzy-matching file selection (using cmt-T),
                    > so I recreated its gui using Python and PyObjC. If you're not familiar
                    > with it, pressing cmt-T brings up a window containing a text box and a
                    > list of all files in the cwd and below. Typing into the text box
                    > narrows the list of filenames. It has a couple of other niceties (such
                    > as fuzzy matching).
                    >
                    > 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").
                    --~--~---------~--~----~------------~-------~--~----~
                    You received this message from the "vim_mac" maillist.
                    For more information, visit http://www.vim.org/maillist.php
                    -~----------~----~----~----~------~----~------~--~---
                  • Jjgod Jiang
                    ... 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
                    Message 9 of 10 , Dec 31, 2007
                      On Sun, 30 Dec 2007, Nicholas wrote:

                      > 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

                      --~--~---------~--~----~------------~-------~--~----~
                      You received this message from the "vim_mac" maillist.
                      For more information, visit http://www.vim.org/maillist.php
                      -~----------~----~----~----~------~----~------~--~---
                    • Nicholas
                      ... Yep -- I don t actually want anything from Vim proper, I just want to be able to pop up a window. It seems like the GUI part of MacVim is the best place to
                      Message 10 of 10 , Dec 31, 2007
                        > > 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?

                        Yep -- I don't actually want anything from Vim proper, I just want to
                        be able to pop up a window. It seems like the GUI part of MacVim is
                        the best place to do this, because then it can be integrated with the
                        rest of the app -- rather than popping up a separate appicon, not
                        being modal, etc, which is what you get if you create a run loop in
                        the core vim process, which is what seems to be happening now.

                        > 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.

                        Yeah, it would be cool if it were somehow possible to get the best of
                        both worlds -- easy access to GUI elements, but also be able to act
                        like a normal Vim python plug-in. :)

                        --~--~---------~--~----~------------~-------~--~----~
                        You received this message from the "vim_mac" maillist.
                        For more information, visit http://www.vim.org/maillist.php
                        -~----------~----~----~----~------~----~------~--~---
                      Your message has been successfully submitted and would be delivered to recipients shortly.