Tuesday, May 15, 2007

This Blog is (obviously) pretty much dead, because now there's wiki.macvim.org :-)

Tuesday, October 03, 2006

Keyboard handling patch

Update: This patch got accepted into the official vim source (patch 7.0.138). Yay!

Mac Vims Carbon keyboard handling code doesn't apply modifiers (like shift) to special keys like the arrow keys. I wrote a patch to take care of this.

Of couse, this patch causes a few regressions (which I'm trying to fix).

I have to test the following keys with each version of the patch to make sure the regressions stay fixed:
  • C-V S-Left should insert "<s-left>" in insert mode. Done by original patch.
  • Mappings like
    map <c-e> <end>
    map <c-a> <home>
    should work (insert mode and normal mode) (regression found by Kyle Wheeler).
    Fix: Don't send CTRL modifier for keys with ASCII code < 32
  • C-F and C-B should work in normal mode (regression found by Bram Molenaar). Seems to be fixed by the patch that fixed the previous problem as well.
  • Shift-Tab should give previous match in command line completion (found by Bram Molenaar as well). simplify_key() seems to mess up the shift-tab keys. Shift-Tab is a special key and has to be send as such.
  • Shift-Space has to work (the code that removes shift from chars like (, *, + etc. removes it from space as well).
  • Unicode characters (ä etc.) should work (they are broken because of the Shift-Tab patch at the moment).
  • :map ç j doesn't work
Generally, modifiers required to generate a key (shift is required for uppercase characters or * etc, alt is required for ç (at least on my keyboard), etc) should not be sent to vim. Is there a way to find out which modifiers are necessary for a given character? This depends on the keyboard layout of course.

Notes: Keyboard layout files; this seems to be what I'm looking for
The latest version of the patch can be found here.

Sunday, August 27, 2006

Green Circle of Confusion

Do you know what the green circle in the title bar of your windows does? What happens if you option-click it? You're not alone.



According to Apple's HIG, it toggles between a user state and a standard state -- it doesn't maximize your window -- and the HIG explicitely advice against maximizing your window. However, this is exactly what Carbon's standard window handler does. If you want to change it, you are advised to write a listener to the kEventWindowZoom event.

However, implementing the kEventWindowZoom yourself is a bad idea, because no one really knows what this button should do. Try Option-Clicking the zoom box in several apps and see what happens for instance. Finder, for example, does weird things. But, hey, we're used to that, aren't we?

Fortunately, you can get around writing your own kEventWindowZoom handler most of the time. You only need to implement an kEventWindowGetIdealSize handler and return the standard state size of your window. The standard window handler does the rest. Option-Clicking moves the window into the upper left window, as it turns out. Here's how Vim responds to that event:

static OSStatus onWindow(EventHandlerCallRef handler,
EventRef event, void *data)
{
Point p;

UInt32 attributes;
GetEventParameter(event, kEventParamAttributes, typeUInt32, NULL,
sizeof(UInt32), NULL, &attributes);

switch(GetEventKind(event))
{
case kEventWindowGetIdealSize:
/* ideal width is current */
p.h = Columns * gui.char_width + gui_get_base_width();
/* ideal height is as high as we can get */
p.v = 15 * 1024;
SetEventParameter(event, kEventParamDimensions, typeQDPoint,
sizeof(p), &p);
break;
}

return noErr;
}

Thursday, August 24, 2006

Notes on porting Vim Mac to Carbon Events

Vim for Mac still uses the seriously deprecated WaitNextEvent() api. Using Carbon Events (especially the standard event handlers) should make the code shorter.

Before porting to Carbon events, gui_mac.c is about 6500 lines (with gui tab pages).

Plan: Replace WaintForNextEvent() with RunApplicationEventLoop() (and use CreateNewWindow() instead of NewCWindow() in gui_mch_init()), use standard event handler. Check what codes needs to be changed. We need callbacks for
  • Keyboard events (seems to be already in place)
  • Mouse events
  • Menu events
  • Control events
(wow. what a superfluous list.)

Stuff that's influenced by a change to Carbon Events and the standard event handler:
  • proxy icon handling is done automatically (as soon as proxy icons are supported)
  • toolbar config stuff is done automatically (as soon as there's a toolbar)
  • window movement, app activation, menu handling...
  • window resizing becomes life (can prolly be prevented if this turns out to be annoying, though)
  • drawing is automatically double buffered (it's prolly buffered atm as well, so this is no real change) -- think about drawing code
  • gui_mch_wait_for_chars() (or whatever it's called) has to work with the event stuff -- see gui_win48 how they do it
  • Control handling code should get easier (at least once controls are used in the osx way)

Important functions to convert:

  • gui_mch_wait_for_chars() (calls WaitNextEvent())
  • gui_mac_handle_event()


Stuff to take care off:

  • redraw only up to N (˜ 25) times per second (measure fps? prolly overkill)
  • scrolling must not be allowed under certain cirumstances (allow_scrollbar)

General Notes
  • Standard App Handler is called automatically by RunApplicationEventLoop(), Standard Window Handler has to be specified with the kWindowStandardHandlerAttribute (in CreateNewWindow() or ChangeWindowAttributes(), preferably the first)
Resources

Gui Tabline

Note: The patch for the drawer version is available at macvim.org.

Vim7 added support for tabs. However, the mac version doesn't have gui tabs.

There are several ways to implement gui tabs in mac vim:

Segmented view

Pros:

  • Tabs like you expect them
  • Doesn't need much space

Cons:

  • Needs OS X 10.3
  • needs compositing enabled
  • seems that this needs a standard event handler on the main window, which makes resizing and maximizing choke. Without the standard handler, clicking the tab bar doesn't work...perhaps this can be fixed without a standard handler?

There are two ways this can be implemented:

  1. Put the segmented view in the root view of the window. This has the advantage that it works with less effort and gives more vertical room for vim (but makes moving the window with the mouse somewhat harder). Another problem is that no title bar text is available, this is annoying if you use Expose for example. Additionally, it looks really ugly.
  2. Put the segmented view in the content view of the window. This requires more changes (vim's text window has to be converted to a view, which are only supported from 10.2 on), but it's what you'd normally expect. Plus, if the text area is a view, this gives us the ability to add a toolbar as well; it should also improve drawing performance and is recommended by apple as the "future".

The segmented view should change its size when the window is resized, if there are a lot of tabs, they should be made smaller so that they are all visible. Alternatively, left/right arrows can be added after a certain minimal tab size (see this page for an example).

It looks like this:

Vim with a segment view tabline

todo: make tabs clickable ( gui_mac_doMouseDownEvent ?), make tabs smaller if they don't fit otherwise, resize max toolbar size when window is resized

Drawer

Pros:

  • works with older mac os x versions (10.2)
  • Doesn't need vertical screen space
  • has room for a lot of tabs. the drawer could display tabs hierarchically, this way you could have whole trees open.
  • other gui stuff could be added to the drawer

Cons:

  • unexpected
  • needs some horizontal screen space
  • according to this, data browser doesn't work with compositing on 10.2, but drawers need compositing. so this might not really work on 10.2 :-(

It looks like this:

Vim with a drawer "tabline"

todo:
crashes when -p *.h is used (stl=1, close all but the first tab, open new tab) (might be fixed by now, was unable to reproduce this), crashes when doing sta=1, set lines=20, set lines=40, tabe . q, tabe . (fixed in v4), if the window size is set to a smaller than minmal
height with :set lines=10 the display looks really strange, scrollbar flashes black on tab change, context menu close is only applied after mouse move (probably some event stuff)

One window for each tab

Use a separate window for each tab. This would be very maccy, but has probably some problems because the windows can have different sizes.

External tab lib

Use this tab control.

Pros

  • Looks good, is what you'd expect
  • maintained by others, and used in other apps (iterm,colloquy, adium
    want to use it too)

Cons

  • The lib is in cocoa, so we need a wrapper to call it from C.
  • Needs views as well

Stuff to test
  • :tabe äö (this killed a few of my vims)
  • :tabe aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa (check what happens with long file names...should be shortened somehow)

I've implemented the segmented view and the drawer variants. I like the drawer version so much that I'll keep it for now. You really get used to having 20+ tabs open, and only the drawer version supports that.

Brainstorming

Stuff that could be improved in mac vim:

  • add proxies to the title bar, call SetWindowChanged (see here for details) - gui_mch_update, gui_mch_flush. Window proxies see here: AliasHandle, SetWindowProxyAlias, IsWindowPathSelectClick, WindowPathSelect (and SetWindowModified of course)
  • improved atsui stuff (draw_string_QD/draw_string_ATSUI)
  • (more than one window per session...)
  • generate "Press Enter or enter command..." message, tab, cmd-tab: more messages are generated
  • trackpad scrolling is currently a bit jittery because left/right movement scrolls as well (so left/down movement jitters) done
  • ctrl-click for context menu, then click somewhere else - another popup is opened done (not by me)
  • (not mac specific) when a file is selected in :e . , the :pwd part should be stripped if the file is somewhere below pwd
  • pum shouldn't flicker (don't redraw too soon?)
  • use carbon events
  • use hiview
  • Vim->About should work
  • use mac os built-in spell checker :-P
  • activating left scrollbar doesn't really work
  • repainting whoes (scrollbar on/off; select new tab via drawer, :set cursorline etc)
  • :set cursorline should move highlight and cursor at the same time, currently cursor is moved, screen is redrawn, and then the line is moved (and the screen is again redrawn)
  • Fullscreen mode ;-)
  • :map <d-a-c> doesn't work (<d-s-c&gk; does work, though)
  • scrollbar thumb should be of the appropriate size
  • font selection dialog should be modeless
  • font antialiasing that works! (aquamacs is able to do it)
  • resize frame should only show allowed increments (better yet: life resizing)
  • start to resize the window, hit escape, move mouse -- vim explodes
  • drag-n-drop from/to tab drawer (cf. proxy icons as well)
  • drag-n-drop tab reordering
  • antialias doesn't work with macatsui, umlauts don't work without macatsui
  • convert the ugly dialog boxes to sheets, add better keyboard support to them (if they are left as dialog boxes, they should be moveable at least)
  • remove "Help" item from context menu
  • Use FSRefs instead of paths everywhere

other mac text editors one can look at for some inspiration ;-):

There's nothing to find here

I want to make some changes to vim for mac. This blog is solely for keeping notes on my progress (if any).