Hacker News new | past | comments | ask | show | jobs | submit login
Kakoune – A Modal Text Editor (github.com)
144 points by bibyte 49 days ago | hide | past | web | favorite | 58 comments



I like that there's a push now for these reconsiderings of older systems that are still in common use. Vi/vim has been around forever, and has survived all sorts of other editors emerging as competitors.

Kakoune is an interesting concept because most post-vi editors have abandoned modality, and Kakoune embraces it wholeheartedly in an attempt to capture the essence of what makes vi powerful and attractive for a certain type of user, but trying to ditch some of the historical ed/ex syntax and thought patterns that make vi weirdly inconsistent. I don't think kakoune is quite there -- I think the multi-selection gimmick is not strong enough to be worth being first-class (especially the way that search-and-replace works), too many common operations are chorded, and there's no selection "mode" -- you have to remember to keep pressing 'J' as long as you want to grow the selection; one 'j' and you're lost.

In programming languages I think we're seeing this happening also; C has remained a prominent language despite its age and the number of C-killers that have emerged over the years, and now we're seeing a resurgence of projects that are really trying to preserve something at the heart of C that has made it attractive for so long, but that even the most jaded systems programmer can see are not ideal, like the fact that types precede names in variable declarations, or the lack of a keyword for function or variable declaration that make it hard to grep, or the superfluous parens in ifs and fors that are obviated by mandatory blocks, or the default pass-through behavior in switch statements. Previous attempts, like C++ and D, have diverged too much from the simplicity of "I can imagine what the assembly code for this function will look like based on the compiler in my head", Rust has some attraction, but nim and zig and Jai and v are all emerging to nuzzle into that niche by restricting their feature set.


>even the most jaded systems programmer can see are not ideal, like the fact that types precede names in variable declarations,

Honestly, I find it shocking anybody can hold this opinion.

I hate that every single new language insists on types being on the right. I searched for a reason why this is, and typically the results are along the lines of type inference being easier to implement. I'd prefer to take no inference at all and have my types on the left, where they belong. I'm totally serious.

Types on the right are a readability disaster.


I agree. It's such an illogical and unreadable construct to me. Even after working with a typed language for awhile my instinct is to declare the type before the variable name.

I've been envisioning a future programming environment that automatically aids in code readability by hiding unnecessary information when you're not using it. Manual code folding was sort of a first step, but this environment would take it further by hiding things like types until you need them. So something like

  proc eval(c: Criterion, token: Token): bool =
    let tokenCrit = (token.identifier, token.token)
    return tokenCrit == c
Might look like

  proc eval(c, token) =
    let tokenCrit = (token.identifier, token.token)
    return tokenCrit == c
Or even

  proc eval(c, token) =
    ...
    return tokenCrit == c
It would have to be smart enough to expand the hidden blocks when you need them and in an unobtrusive way. It's also possible that the type declarations wouldn't actually expand in this editor, but would be set by some sort of popup selector (similar to how autocomplete works, but you'd select the variable type).

This is just a rough idea and I'm not sure how well it works in reality. But when code starts looking like `proc add*[T](root: var BinaryTree[T], n: var seq[BinaryTree[T]]) =` it starts to lose its at-a-glance readability.


Gary Bernhardt has a good take on this in his talk A Whole New World [1]. He introduces an editor which has these layers which can display or hide orthogonal information such as types, a short view or profiling details. That talk, and your comment and my inability to find anything that does this kind of work simply surprises me. Are there no good examples of systems that allow these kind of simple transformations out there? I remember someone pointing me to a clojure editor a while back, maybe? I can't remember.

Seems to me there is a desire for editors that allow a user to transform code, whether it be annotations or raster graphics as Bernhardt puts it. The closest I know of is org mode, and how it works on a plaintext interface but has no qualms about displaying it in wildly different ways than an org file might look opened up in vim, though it still does maintain readablity. I think this is the way to go and I've been playing around with a personal workflow on top of org mode lately. What do you think?

[1]: https://www.destroyallsoftware.com/talks/a-whole-new-world


For me it's about compactness of type representation -- types are on the right, except when they're not -- in arrays or function pointer declarations, you have to deal with the fact that the variable name being introduced may be nested in unintuitive ways deep inside the declaration. By moving it to the right, you make that much clearer. In Java, they made it so that array information went on the left, which made it a little clearer, but was still kind of ugly, and Java really had no notion of function pointers anyway.

The other problem with the type-on-the-left is that variable declarations are hard to find without tooling designed for that purpose. Being able to search for "var x" is a nice feature that makes it easy to separate out the declarations from the usage.

I agree that type inference and optional types is something of an anti-feature from my perspective as well; even more frustrating is languages that treat a type declaration as a type assertion rather than a declaration, which serves to divorce ideas about physical storage from the code; abstract types like "bool", though, have already crept into C to make the type model a little more complicated than it has to be. Types in C used to be declarations of storage class as well; now I know that a bool in a struct will take up a byte, but that byte and bool are not really compatible types makes it a little harder to reason about, even if that does give better hinting to the compiler.


Types on the left are a parsing disaster. At the very least, a C-style definition demands too much parsing power for questionable benefits. It blurs the boundary between types and expressions and thus complicates essentially everything that has to deal with source codes. This has nothing to do with type inference.

If type expressions were readily recognizable from other expressions (for example, you can force types to be CamelCased and assigned different lexical classes like ML) then it'd be probably a pure personal taste. But a C-style definition? Big no-no.


It's not like we don't have enough power with our modern CPUs.


I don't know, take a look at this random Haskell function from Yesod[1]:

  isValidPass :: Text -- ^ cleartext password
              -> SaltedPass -- ^ salted password
              -> Bool
  isValidPass ct salted =
      PS.verifyPassword (encodeUtf8 ct) (encodeUtf8 salted) || isValidPass' ct salted
The stuff after `::`, including the following indented lines, are the type of this function. The text after the `--`s are comments.

That's a very, very simple one. Take look at this other type signature:

  widgetToPageContent :: (Eq (Route site), Yesod site)
                      => WidgetT site IO ()
                      -> HandlerT site IO (PageContent (Route site))
or this one:

  selectFieldHelper
          :: (Eq a, RenderMessage site FormMessage)
          => (Text -> Text -> [(Text, Text)] -> WidgetT site IO () -> WidgetT site IO ())
          -> (Text -> Text -> Bool -> WidgetT site IO ())
          -> (Text -> Text -> [(Text, Text)] -> Text -> Bool -> Text -> WidgetT site IO ())
          -> HandlerT site IO (OptionList a)
          -> Field (HandlerT site IO) a
Do you think it would be more readable if the type came before the identifier?

I know these types might look needlessly complicated to someone that doesn't know how to read them, but when you learn to understand them, they are a blessing. Most of the time, a type will tell you everything you need to know about a function or other value. They're often better than the documentation to know what they do.

Another advantage is that they simplify looking for the type signature of a function. You just need to `grep '^identifier'` instead of what you would do for C++, for example, `grep 'identifier\('` and manually filter out the calls.

Also, having it on the right permits one to comment on different parts of it, just like one would do with non-type code.

I don't see the sense in ever having it on the left (where's the benefit? just having it look like C?), but I guess it's not unacceptably bad on unexpressive type systems where the type is hardly more than a type identifier.

[1] https://www.yesodweb.com/


I don't know that you'll be able to sell a programmer that has stuck with C on Haskell. The ability to look at code and have a rough idea of what the assembly will look like is, in my opinion, fairly high up on the list of desired features. Haskell does ... not really provide that.

And as for greppability, it has become very common now to use keywords, which were very common once upon a time but went out of favor with Algol, so that you get declarations like "fn isValidPass(...)" to make grepping even easier.

And easy grepping also means easy parsing, which works both for machines and for humans when you're trying to digest unfamiliar code.


> I don't know that you'll be able to sell a programmer that has stuck with C on Haskell. The ability to look at code and have a rough idea of what the assembly will look like is, in my opinion, fairly high up on the list of desired features. Haskell does ... not really provide that.

I'm not trying to sell Haskell to C developers, though, I was just replying to the GP's disbelief at a syntax preference for having types on the right. Also, I don't think the ability you mention has anything to do with the choice of syntax of having types on the left or the right.

I do very much wonder if there are any benefits, at all, of having the types on the left.

EDIT: On re-reading my above comment, I guess I was selling it a little, but I only meant to justify having complex looking types. :P


The notion of types as type assertions is relatively new to C, and its syntax reflects that. Types in C are more storage specifications than they are type assertions. When you declare an “int”, you’re not declaring a variable of type int per se; you’re declaring and int-sized hole where you can put values.

So the declaration on the left [ed: Was right] makes a certain amount of sense - you’re declaring an int, so that’s what you lead with. When you declare a “string” you have to think about how the string is stored; and that implementation detail bleeds into the syntax.

A C has matured the notion of incompatible types has seeped into the language to the point where now it becomes a little annoying that I can just go ahead and pass an int into a function that expects a typedef’d “type”; libraries often wrap them in very lightweight structs just to get an additional bit of typechecking. The expectations for what kind of errors the compiler can catch have grown over time but the language has only made small concessions.


> the declaration on the right makes a certain amount of sense - you’re declaring an int, so that’s what you lead with.

I'm sorry, but that doesn't make sense to me. You say it as if it's the only sensible way to design a declaration syntax, but Haskell (and other languages) did it the other way just fine. I don't see how the differences in semantics between the 2 type systems give rise to a benefit in having the type expressed on the left.

If the design came to be decided like that, it seems it's simply not something that was put much thought over. That's fine too, since the limitations of the type system do not give rise to cases where this syntax choice becomes too big of an inconvenience.

Still, no benefits as far as I can see. Maybe it simply appealed to the designer's intuition more. Choosing because of that indicates that the choice was pretty arbitrary, though.


Sorry -- I edited my reply above; the quoted sentence should be "the declaration on the _left_ makes a certain amount of sense".

> You say it as if it's the only sensible way to design a declaration syntax

I don't say that -- in fact, I'm replying to my own post saying that the declaration on the left was a mistake. My only point is that it is a design decision that has some historical grounding.


> Do you think it would be more readable if the type came before the identifier?

This is an unfair comparison, in C, only the return type goes before the function name, the argument types go inside the parens.


I'm super curious about your strong opinion on this, especially since it's seemingly stated as something more universal than just your personal preference (i.e. "readability disaster"). Is there anything specific about types being on the right that you feel makes them objectively worse, or do you just personally not like them (which is totally valid and would be much more understandable to me)?


Nim is certainly not a language I would qualify as having a "restricted feature set". Jai is mostly under wraps but from what I've heard from the author, while it very strongly opposes some common language features that C doesn't have, it will also bring quite a few unusual features.

Thanks for pointing out v, which I didn't know about!


> I think the multi-selection gimmick is not strong enough to be worth being first-class (especially the way that search-and-replace works), too many common operations are chorded, and there's no selection "mode" -- you have to remember to keep pressing 'J' as long as you want to grow the selection; one 'j' and you're lost.

Agreed. I also don't like that this system requires you to have what are essentially duplicate keybindings with the only difference being that one does the motion while starting a new selection, and the other does the motion but keeps (and extends) current selection. It guess it's supposed to be ergonomic, but I think it's too wasteful and in wasting so many possible keybindings, we're trading ergonomy away by not being able to bind more powerful functions to all these spent keys.

I'm not sure what the solution should be. I like what Kakoune is trying to do, but I don't think they landed on the right idea.

I'm not sure I'd like having to toggle selection mode on or off. I think it'd be better to always be in the selection mode; then if you don't want all your recent navigation selected, you press a key to reset the selection. The obvious downside is that you'll end up having to reset the selection a lot. On the other hand, if it's only one easily accessible key, it might work well enough.

A slightly more advanced solution would be that you always have a selection formed automatically from the latest motion, plus a mark (perhaps any number of marks) that can be used when you need to combine multiple motions. Normally editing commands that take a selection would only operate on the most recent motion, but with a single prefix or postfix key could be extended to apply up to the mark.

Whatever it is, I think there's got to be a way to improve on vi without making as many tradeoffs as I think Kakoune did.


I think the problem with any sort of selection/motion combo is that a selection has two endpoints (limiting to just single-selections; multi-selections and cursor make this a jillion times more complicated).

When you make a motion you have to decide which one of the endpoints is the current cursor, and that's where I feel like you run into trouble. "Grow the selection up by one line" is a hard notion to express when you started by selecting down. Vim has visual select mode, which has a line-based, character-based, and block-based mode. I'm not totally sure that we need them to be distinct.

The problem is that kakoune now has me vaguely dissatisfied with both vim and kakoune and I don't like it.


I don't think the the two endpoints are that big of a deal. I know where I want to start selecting, so I can just navigate there and then expand the selection in one direction only. This is how it works with vi anyway, only you can't really expand the selection after the fact.

In the rare case case when I miss the mark, I wouldn't mind pressing an extra key to move the cursor to the other end of the selection and expand from there.

And yeah I feel that dissatisfaction too.


That extra key is o in vim's visual mode. It moves the cursor to the other end of the selection

With the text below, your cursor is the pipe character. From the cursor position, in normal mode, press 'vjok'

    line1
    line2|
    line3


Using kakoune for the first time made me understand how much better the vim keybindings could be. I switched the weird begin & end of line navigations (0 and $) to (gl and gr) as they are in Kakoune, and I also added the move view (v* in kakoune) commands to vim.

Also my goodness having built-in multiple cursors is fantastic. Kakoune multiple cursors is much much better than the vim plugins for multiple cursors.

As other people have said though, there are some plugins that have yet to be ported to kakoune. iirc smooth scrolling (comfortable-motion) and vim-wiki to name the ones that come to my mind.


That's a cool idea with gl and gr. I've never used 0 and $ in vim, D or C get me to the end, and I have what is probably an anti-patter in hitting I<esc> or A<esc> to get to beginning or end otherwise. Or its a change inside quotes or parens or db.

One funny anti-pattern I just noticed I have recently is when editing the last line I've written in notes I'll open a new line with O then immediately exit to normal mode, only to have the next thing I do be to hit i for insert.

I guess my long winded point is that it's easy to have anti-patterns sneak up on you and it's nice to see someone else's re-designed keybindings on a modal style interface to spur reflection on our own setups.


I still sometimes have the A<esc> anti-pattern. It's slowly been disappearing since I added gl. The kakoune keybindings were designed with a lot of thought behind them. They seem extremely natural.

Also, I meant to say that the my replacements for 0, $, gg, and G are gh, gl, gk, gj. 'g' for 'go' and 'hjkl' for the standard up, down, left, or right.


I saw this about a year ago, since I was curious if there were any editors outside of the Vi(m) family to embrace modal editing. I installed it and then forgot about it.

Sadly, even though this looks amazing, I don't see myself using it until most of the plugins I use for Vim have been ported over. Does anyone here use Kakoune as their daily driver? Do you feel it's worth the switch from Vim?


I switched from Vim to Kakoune about two years ago, after nearly 20 years of vi / vim. Being essentially in visual mode all the time clicked for me very fast. Since I don't use plugins, there was nothing holding me back.

I still use vi / vim for some of the usual suspects. I haven't bothered to change my $EDITOR, so I always default into vi unless I explicitly invoke kak. (Like right now, w3m invoked vi for me to write this comment.) And then there's visudo, which is far too much of a pain to set up for using kak. And kak doesn't to my knowledge have anything like vimdiff. Also, it doesn't work as well for what I call "interactive sed," where you do a global regex replacement. For ordinary source code editing though, I'm not going back. Selection-oriented editing with multiple cursors is just too much fun.


One of my favourite things about Kakoune is global regex replacement. In Vim, it usually goes like:

- Type `:%s/`

- Spend 30 seconds thinking up a regex which will hopefully match all the things I want to change, and none of the things I don't

- Write it out, hit Enter

- Run my tests, or run "git diff", or generally review the changes, and find a bunch of stuff is broken

- undo, restart from scratch

You can sometimes avoid screwing up the entire file with the "c" flag that asks for confirmation for each change, but it's too easy to get bored and distracted and type "y" too many times.

In Kakoune, a global regex replacement goes like:

- Type `%s`

- Spend five seconds thinking up a regex that approximately matches the things I want to change

- Interactively do any additional adjustments that are difficult to express in regex, like the `M` command that extends the selection to the next matching bracket

- Cycle through matches with `(` and `)`, checking to see if they're what I expected

- If not, I can remove individual selections with Alt-Space, or just hit %s and adjust my regex

- Type `c` and actually make the change

Because of the whole "multiple cursors" thing, I can get fast feedback on each part of the process, so I can get the result I want much more quickly.


I'm not arguing that Kakoune's way isn't better (I think it probably is). But you can sort of do this in Vim as well, minus the more advanced interactive adjustments:

- :set hlsearch

- Type `/`

- Spend five seconds thinking up a regex that approximately matches the things I want to change

- Hit Enter

- Cycle through matches with `n`/`N`, checking to see if they're what I expected

- If they're not, press `/` then <Up> and edit the regex

- When satisfied, type `:%s//`, enter the replacement you want to make, then `/g<Enter>` to apply the change everywhere


You can also just change the command to something like :%s/regex/replacement/gc

The "c" modifier makes you confirm each replacement, and you can y/n for each of them.


I'm not sure what's the library providing the functionality, but regex replace is super nice in the Spacemacs emacs distribution. It takes the same arguments as vim, but shows and highlights the changes your regex will do while you're writing it out.


Much as I love kak, multiple selections can work against you for this use case. If the file is big enough, and there are enough matches, kak falls over long before vim breaks a sweat. I'm happy to use vim for one thing and kak for another.


I posted it on here some time last year and tried switching from Vim.

The only thing stopping me was my inability to configure it to use different indentation settings per file type.

I'll definitely try again at some point. I love Vim and have used it for nearly twenty years, but Kakoune's grammar just makes more sense in several ways.


I've been using it as daily driver for a while. I switched when I realized I'm constantly tried to use Kakoune editing commands in Spacemacs...

Do you mind listing plugins you miss? That's probably depends on use-case but my impression is most of essential stuff is already available.


I don't mind, but I currently use Fireplace for Clojure, Intero NeoVim for Haskell, and the vim-fsharp plugin. As far as I'm aware, there are no direct ports of those for Kakoune.


Fair point, Kakoune still lacks when it comes to in-depth integration with tools for specific languages. There is good LSP integration but unfortunately LSP alone won't turn editor into IDE.


Me personally, I'm more of a Larry Tesler (https://en.wikipedia.org/wiki/Larry_Tesler) kind of guy:

> [Tesler's] career forms a link from the pioneering work of Doug Engelbart, Stu Card and Tim Mott, to the emergence of a dominant design for the PC, as described by Bill Atkinson, Cordell Ratzlaff and Paul Bradley.

When he was at Apple, Larry Tesler had a license plate saying “NO MODES.”

(from http://www.designinginteractions.com/interviews/LarryTesler)


> NO MODES

That's a lie though. All GUIs have modes all over the place. For example:

- When I click into a text field, I go into Insert mode.

- When I tab away from the text field, I'm in some sort of Select mode.

These are clearly different modes because keys will do different things depending on the situation (e.g. [Space] in Select mode will click the focused button, but in Insert mode will insert text into the focused text field).


Also a rule from the CEO in the book "Soul Of A New Machine", who commanded his engineers "No mode switch".


I've been trying out Kakoune for a while, using it in parallel with neovim. The differences in keystrokes are tricky but I've found that I can compartmentalize (0, $, and x are dramatically different and in my frequently used category for vim).

The biggest gripe I have is that there is no differentiation between selection mode and regular mode, which makes line selection or line deletion more complicated than it has to be -- 'xd' will delete the current line, unless the current line is empty, in which case it will delete the next line.

The reason for that makes sense in kakoune's model, which is that when the cursor is sitting on the EOL of the current line, the trailing \n is selected, and 'x' will select until the next \n (to support moving forward if the current line is entirely selected).

Otherwise the model is very nice, and the programming model (which is basically "let shell scripts do the heavy lifting") is actually surprisingly nice for implementing extensions.


Been using Kakoune for .. no idea, a year+ now after many years in Vim. It's great. It has some things I dislike (like reliance on shell for idiomatic plugins), but overall the meat of Kakoune - ie the selection based editing is something I cannot live without.

These days I tire of Terminal programming and have been wanting to escape it for more rich UIs, but while I have been searching I am confident my end choice must support modal editing and selection behavior akin to Kakoune - so I can replicate the UX of Kakoune. As it stands I imagine my choice will be Xi Editor, once it gets better support for modal editing and multiple cursors.



I've been using Kakoune for about a year, after a year of vim, after several years of Sublime. It has its warts, but it's way above and beyond anything I've used before. Whenever I use another editor I feel freakishly slow now. The big non-editing related thing it did for me was to make me appreciate the unix way — it really does one thing really well, leaving window management to tmux, and plugins to shell scripting, while maintaining its own client-server architecture to decouple various components. I'm not a huge fan of tmux or bash for scripting, but the open-endedness of kakoune's architecture on top of the great editing model really makes it a safe choice to invest in.


I tried Kakoune for a few days a while ago. Mostly I was in a position where I stumbled a lot from things not lining up exactly with Vim, but I also didn't see what advantages I'd get from switching over. Can someone who has used both Vim and Kakoune describe why you might choose to switch?


In my case, I was always in visual mode. The mental gymnastics required to figure out what motion comprehends the text I'm interested in was too distracting otherwise. So when I tried kak, it was easy to pick it up -- like visual mode, but always on. And with what I found to be a very consistent set of keybindings.



From the screenshots, apparently they decided that what's really missing from modal editors was Clippy!?

Oh, wait: https://github.com/gbigwood/Clippo


     __                 
    /  \        _____________ 
    |  |       /             \
    @  @       | I make Vim  |
    || ||      | much more   |
    || ||   <--| friendly    |
    |\_/|      | and easy.   |
    \___/      \_____________/


The way I use vim is predomenantly as a plugin to give modal editing powers to my editor of choice (Sublime, Atom, VSCode, etc.) I would love to be able to try out Kakoune in that way. Do any such plugins exist?


Last I looked (maybe a year ago) there were none. I have the same concern you do, I could use it directly but I need to use other environments often enough that I'd constantly be switching back and forth.


Is there an Evil mode equivalent for using these keybindings in Emacs? In fact, can Evil be extended to support Kakoune bindings?

I’d like to try out the paradigm without losing my current productivity.


> In fact, can Evil be extended to support Kakoune bindings?

Of course. I just don’t think it has been done yet. Was tempted to try it myself.


EDIT: Here is reddit discussion about it

https://www.reddit.com/r/emacs/comments/926a9n/kakoune_editi...


I can't tell from the readme. What keybindings are available in Kakoune that aren't in Vi/Evil?


In its most basic form, the order is reversed so that the selection is specified before the action, like visual mode in Vim but on all the time and a little more powerful. It feels much more interactive than the vi design.


That actually sounds pretty neat.


For me, the advantage of vim no longer lies within the original vim editor, but in its ubiquity -- I can have all the advantages of Sublime Text, VS Code or whatever and still use (mostly) the same keybindings thanks to various vim plugins.

I'd consider switching if there was a viable plugin for my current main editor or, better yet, something similar that NeoVim is trying to achieve (i.e. running actual vim as background process for these plugins instead of emulating).


I have been interested in Kakoune before, and I have never been able to nail this answer down:

Does Kakoune feature IDE-style omnicompletion? Like Elixir module name and function completion.


To some degree; your best bet is LSP integration but so far things have been a little flakier than I like because my environment is strange. But given the architecture of their extensibility model I'm extremely optimistic.


I believe kak supports LSP, although I haven't tried. By default, it offers you completions from all of your open buffers.




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: