vicoapp / vico

Mac Programmers Text Editor
http://www.vicoapp.com/
657 stars 89 forks source link

Autocomplete as you type #15

Closed jordwalke closed 11 years ago

jordwalke commented 12 years ago

Vim's ACP has this, and Sublime has this. I would love to see this in Vico. I've tried to implement it using Nu, but I hit a wall. Now that we have the source, it's likely much easier.

Shadowfiend commented 11 years ago

The idea here is simply that the completion popup be triggered while you're typing? What would be the criteria for bringing it up?

jordwalke commented 11 years ago

@Shadowfiend : Like in many other editors (Sublime/VisualStudio), as you type characters (longer that X) it searches open documents (or some other configurable index) for words that begin with that prefix, and pops up the completions below. Vim's famous ACP.vim plugin does this in a way that's similar to Sublime. (Emacs has a plugin as well.)

If an open document contains: "Hello There". And in any other document, you were to type "He" - it would pop up "Hello" as an option. Hitting enter or tab would select that first match. (Most allow configuration of enter vs. tab to select).

Shadowfiend commented 11 years ago

So in your mind typing a 2-letter prefix would be what sets it off? I've used editors with autocomplete before, just trying to get a feel for when we bring it up at all.

jordwalke commented 11 years ago

Yes, two letters is usually a great way to quickly filter out a huge number of possibilities. One letter is usually overkill. The key is that it should be two characters after any word break (like punctuation etc). A lot of this could/should be configurable IMHO.

Shadowfiend commented 11 years ago

Yeah. This is definitely a larger feature; if anyone wants to take up the gauntlet, that would be cool. I've got a few other big features I want to take care of first, so it might be a while before I can look at this.

Before all of that I'm going to try and clear out some of the issues that have already been filed here, though. Most have been pending for a tad too long.

jordwalke commented 11 years ago

Understandable - thanks for continuing development on this very promising editor. I feel the auto-complete-as-you-type feature is one of the reasons may people are using Sublime and I'd love to see Vico gain traction.

Shadowfiend commented 11 years ago

Sublime's completion algorithm is also a little more complex than Vico's atm, I think. Still, definitely worth working on (Vico's completion's been annoying me a little lately and I think I have some ideas on how to improve prioritization and such).

jordwalke commented 11 years ago

@Shadowfiend: Can you see a way to get the autocompletion to pop up as you type? I tried to implement this by simply creating a plugin, but the plugin system isn't powerful enough to trigger the popup window. It definitely required some modifications to the core of Vico.

Shadowfiend commented 11 years ago

I'll try and have a look over the next few days to see if I can find an easy fix.

Shadowfiend commented 11 years ago

I've been doing some work on this (work so far is in the completion-as-you-type branch), but it looks more difficult than originally expected. Because the completion popup is currently something that runs modally, keeping up the typing in the main window is not particularly straightforward. So I'm going to have to rework the completion popup to work non-modally, which is going to be a little bit of work. I'll see what I can do tonight.

jordwalke commented 11 years ago

Awesome. Could you help me understand how you would get it to work non-modally? Would you paint it directly on top of the text in the save text view (full disclaimer, I haven't done iOS programming in a long time). If so, maybe we could also think about ways to let plugins (or other features) do other types of painting on top of the text. I'd love to get inline compile/lint errors highlighted directly on top of the text (though I imagine there's a much easier way to do that).

jordwalke commented 11 years ago

I saw this error when Makeing : Apologies if this is something nooby (I'm guessing it's unrelated).

=== BUILD NATIVE TARGET finish_installation OF PROJECT Sparkle WITH CONFIGURATION Release ===
Check dependencies

** INTERNAL ERROR: Uncaught exception **
** INTERNAL ERROR: Uncaught exception **
Exception: *** -[__NSArrayM insertObject:atIndex:]: object cannot be nil
Exception: *** -[__NSArrayM insertObject:atIndex:]: object cannot be nil
Stack:
Stack:
  0  0x00007fff911b1f3a __exceptionPreprocess (in CoreFoundation)
  1  0x00007fff8d914d5e objc_exception_throw (in libobjc.A.dylib)
  2  0x00007fff91158ab8 -[__NSArrayM insertObject:atIndex:] (in CoreFoundation)
  3  0x0000000102d61337 -[XCDependencyCommand createStartedCommandInvocation] (in DevToolsCore)
  4  0x0000000102e0f81b -[Xcode3BuildTask main] (in DevToolsCore)
  5  0x00007fff88ed86b4 -[__NSOperationInternal start] (in Foundation)
  6  0x00007fff88eeb912 ____NSOQSchedule_block_invoke_2 (in Foundation)
  7  0x00007fff90a36a82 _dispatch_call_block_and_release (in libdispatch.dylib)
  8  0x00007fff90a37961 _dispatch_worker_thread2 (in libdispatch.dylib)
  9  0x00007fff8b8b33da _pthread_wqthread (in libsystem_c.dylib)
 10  0x00007fff8b8b4b85 start_wqthread (in libsystem_c.dylib)

make: *** [/Users/jwalke/Desktop/vico/build/DEBUG/sparkle/Sparkle.stamp] Abort trap: 6
Shadowfiend commented 11 years ago

Er… That looks odd. Try re-making? May also want to make sure you've updated the sparkle submodule or whatever… I forget what the crazy git syntax for that is.

As for getting it to work non-modally—what I'm thinking is that we'd let the ViTextView deal with the non-control keys as usual, but also forward them and control keys to the completion controller… Or something like that. That way we'd get typing in the main window as usual, plus handling by the completion controller of whatever else is needed. Still not 100% sure about that, we may need to do some key map shuffling or whatever. The main thing is that the text view would not wait for the completion controller to report a result back before handling typing again, it would instead continue handling typing and the completion controller would process enter/tab and send a message to the text view indicating a completion was selected.

The biggest problem right now is that the text view and completion stuff aren't just used in the regular text views, they're also used in the command box. That's where things get hairy, because we may not necessarily want the two to behave the same. The options there get nasty, because they basically involve using a separate subclass of ViTextView for command line stuff. That's how I see it from the work I've done so far. There may be another alternative.

Shadowfiend commented 11 years ago

I've attached the relevant branch here, it seems to work in my (admittedly not extensive yet) testing. There's an option in editing preferences (“Complete as you type”, also settable via :set autocomplete), which also means you can have autocomplete enabled for certain languages and disabled for others, for example.

I'll probably be using this branch for the next week or so to see how it treats me; if anyone else wants to do that as well that'd be legit.

This also seriously improves regular completion behavior IMO, as the text in the actual editor or command line properly updates as you type, instead of only registering in the completion popup, even if you're not auto-completing.

Currently, completion as you type triggers after two characters. Additionally, while the space key accepts the top suggested completion when you explicitly trigger a completion dialog (via tab/c-n/whatever), when you're auto-completing it does not.

Let me know how it's lookin'!

jordwalke commented 11 years ago

I'd love to try using this, but that error still happens. I've tried git submodule update, recloning, and even switching computers and trying the same (two different versions of OS X). I used to be able to build Vico fine.

Any suggestions?

Shadowfiend commented 11 years ago

Are you on XCode 5 by any chance? I'm currently working with XCode 4.5, and it seems like Sparkle is being sent through an XCode build process.

jordwalke commented 11 years ago

I found out that I had something like export CC=clang in my .bashrc, which was likely screwing things up. I'll try this out for a while and see how it feels. (Compilation now successful).

jordwalke commented 11 years ago

Feels pretty good already. Definitely digging the preference pane option.

One question: By default, wouldn't you say that escape should not only close the completion window, but also exit Vim's insert mode? I've talked with other people about this -- you can tell I'm passionate about type-aheads :) -- and it seems like that's what you want almost all the time. It would be totally fine to leave it as you have it right now, as long as we can show that there is a way to achieve that behavior via key mappings in your site script (do you know if it's possible?)

A couple of other little issues I spotted so far:

Once the little interactions are solid, do you think there will be a way to customize the appearance of the popup through a color scheme (or any other way?) I usually use darker color schemes and the bright white is a bit distracting.

But I can already tell, this seems to make Vico a much better contender to the other popular editors!

Shadowfiend commented 11 years ago
jordwalke commented 11 years ago

That sounds great. Would my custom keymappings that trigger escape work too (I map ctrl-l to exit insert mode)?

Good to know that I can easily fiddle with the color theme code.

Shadowfiend commented 11 years ago

I need to play with it. Obviously we'd want custom keybindings to also trigger things properly while the completion popup is up. I need to see how we can do it without special-casing escape, as I think there's probably some other hidden annoyances related to that kind of behavior that we just haven't run into yet. The biggest issue here is that the behavior of escape when you've hit c-n to trigger it vs when it's autocompleting should be different.

jordwalke commented 11 years ago

It could be optimal to act differently on intentionally opened completions like you suggested. However, it would be convenient (because it sounds easier to implement) if we could convince ourselves that "Having One Way To Do Things" is actually the better user experience in this case. That might mean that escape always closes the popup and exits insert mode, and the user doesn't have to understand when it will exit insert mode and when it won't - it just always does. There would have to be another key-mapping to only close the popup without exiting insert mode. Possibly wishful thinking, but that's actually how I have my autocompletion set up right now in Vim and it works well for me.

Shadowfiend commented 11 years ago

I dunno. I'm going with what my gut expectation is. Until now I've been triggering via c-n, and I always hit escape to get rid of it without exiting insert mode if I found I didn't need it. But once autocomplete was on, I expected escape to get rid of it and insert mode. I think the use cases are different enough that different behavior is merited (perhaps with :set-only setting to indicate what behavior(s) you prefer).

Shadowfiend commented 11 years ago

Ok, those are all taken care of. The font size issue is an existing issue, I just checked, so please file a separate issue for that and I'll have a look at some point.

Meantime, esc and ctrl-[ will properly close both the popup and leave insert mode. Additionally, things like alt-bs will properly propagate to the text view (they weren't before). As long as your custom mapping for leaving insert mode doesn't overlap with the mappings for the completion popup (they're fairly limited), this will pass onto the text view. The text view now closes the popup if it leaves insert mode for normal mode, so that should also trigger the popup to close.

Lastly, the completion popup closes if the caret moves more than 1 space in a single action. This means delete word, backwards word, etc, should all close the completion popup.

The only mild annoyance that remains is that backspace closes the completion popup; however, I will consider that out of scope for this issue. Fixing it in a way that doesn't interfere with the fact that you can remap backspace will probably involve reworking how the filtering of the completion popup interacts with the typing in the text view, which will be a significant overhaul.

Let me know how it's feeling!

jordwalke commented 11 years ago

Trying now!

jordwalke commented 11 years ago

I believe the main pull blocking issue, is that the space bar as a completion accepter really gets in the way. The auto-complete-as-you-type is a great ambient feature that more or less does not intrude on standard editing, but with space bar, that's no longer the case. You really have to think about it. Consider if a text file has this content:

 var x = 'hello';

The next var statement you type is difficult, because autocompletion picks up the first var. To type var y = 'bye'; you must first type var and then hit <space> to accept the completion, and then hit <space> again to enter the actual space. I believe this is why the three main autocompleters that I've tried use either <Enter>, <Tab> or both. I personally like <Enter> the most.

Also, did you try this with sinppets? I think when typing placeholders, something gets messed up.

Shadowfiend commented 11 years ago

Herp? There's explicit code that should disable space as an acceptor when in autocomplete (vs when invoked explicitly). I'll look into it, I haven't noticed that happening at all.

I'll also look at snippets; I don't use them much, so I hadn't tested it with them.

Shadowfiend commented 11 years ago

Definitely seeing some interesting issues with snippets; however, I don't see the issue with the spacebar. If I type var x = 'hello'; followed by var y = 'bye';, I can type both perfectly normally. I wonder if you've added some mapping to space that might be making something strange happen?

jordwalke commented 11 years ago

Great question - I should have checked before reporting the space issue. Aside from the snippets, it sounds like in theory, you've fine tuned the perfect interaction with explicitly triggered completion :)

Shadowfiend commented 11 years ago

Glad you think so :) Note that the action to use in a keyboard shortcut if you want to accept a suggestion with a given key combination only if the popup was brought up from an explicit invocation is accept_if_not_autocompleting:.

Going to investigate the snippet stuff a little more now.

jordwalke commented 11 years ago

That first issue issue was definitely related to my key mappings.

I'm still having trouble having escape and closing the completion window using a single press of escape (when it popped up automatically). I've disable every line in my site.nu file. Any other suggestions?

There's also a strange behavior when completing at the beginning of a word. I really like how you still allow completions at the beginning of text (Sublime gets this wrong - vim's ACP gets this right - this plugin gets it right too).

If you have:

apple
<cursor>parachute

Then typing a makes aparachute appear in the completion list. I believe only apple should show up (that's how other completers seem to work and it ends up being a reasonable behavior).

Shadowfiend commented 11 years ago

Heh, frankly, I haven't tested the behavior at the beginning of a word at all, and it's more accidental than intentional. That implies we'd want the current word to be considered whatever the current word is up to the cursor. If you don't mind, I'd rather fix the snippet issue, consider this particular feature complete, and then consider that change in behavior as a separate issue.

Shadowfiend commented 11 years ago

It does seem like you're right about escape. I could have sworn I had that working, but apparently it was too late and my mind was fooling me. More to come.

jordwalke commented 11 years ago

Sounds fine!

Shadowfiend commented 11 years ago

Ok, I think the snippet issue is fixed. I also think the escape-while-autocompleting issues are actually legitimately fixed -.-

Shadowfiend commented 11 years ago

Fixed a couple of more bugs. However, the . command is still busted with autocomplete (in fact, it was busted with completion before as well—a consequence of the fact that we're tracking key sequences in insert mode for . rather than tracking the final string that was inserted).

Shadowfiend commented 11 years ago

Breakthrough. Completely redid how completions are inserted, which fixes the . command for both auto and manually-triggered completion. Boomtimes.

jordwalke commented 11 years ago

Trying now!

jordwalke commented 11 years ago

I would definitely be proud of your . redo logic combined with autocomplete. I couldn't get it to do the wrong thing after a couple of minutes of trying. Yours could possibly be the very first autocompletion in any Vim-like environment to get that right. Even Vim itself gets that wrong (admittedly because of a bug in Vim that makes it impossible to do correctly).

I just tried some more testing and all the issues seem to be ironed out except for the snippets.

One question: How tightly coupled is all of the logic to the popup window? I suspect we'll eventually want to be able to paint the popup in very different ways (since the popup makes the application window inactive - the close/minimize OSX dots in the upper left corner change color as the completion pops up). But since the general logic here feels pretty solid (once the snippets are fixed) it would be nice to be able to use it outside of the popup mechanism.

Shadowfiend commented 11 years ago

w00t. Good to hear.

What exactly is the issue with the snippets? I didn't get a chance to test it, but it's possible the new completion logic that fixes . re-broke that aspect, which would be sad-face.

As for the logic, it's currently very much structured around the fact that the popup window is modal. That said, the core functionality doesn't rely on it; with some rearrangement, it could be done differently. I agree it's a serious annoyance that the popup is modal for a variety of reasons; the reason it's done that way seems to be essentially so that the completion popup is the one getting the keystrokes, so that it can have its own key mappings. Modifying that will be interesting.

jordwalke commented 11 years ago

Here's a repro of the snippets issue:

Open a .js file. Type for<Tab> and then start typing anything.

Shadowfiend commented 11 years ago

I'm currently running the code with the couple of changes that I've pushed in the last hour, which were addressing some issues directly and indirectly related to snippets, so maybe give that a whirl in case that changed things.

As it is, following your steps, I get a menu prompting me for two different for loop variants and after I choose one things seem to work as expected, with tab moving among the appropriate things. If you tell me what behavior you're seeing and what behavior you expect to see instead, maybe I can get a better idea of what might be happening.

jordwalke commented 11 years ago

It seems like something in your last update has fixed the snippets behavior! I can't see any glaring issues with this (though I've only given a few minutes).

Shadowfiend commented 11 years ago

Sweet! I'm messing around with some stuff and running this branch merged with a couple of others, so I'll probably keep using it for a couple of days and if everything is still feeling good, merge it in. With that in mind, please let me know if you run into any serious problems with it so I can reset that process :)