17 ms·
Vim's 400 line function to wait for keyboard input
- pkaye 11y agoThe question is do you think it could have been done better given that they support multiple OS/UI, etc...
- geofft 11y agoYou can refactor it into multiple functions (#ifdefs around a line containing just "||"? seriously??), some of which are no-ops on some platforms / configurations, and let the compiler deal with inlining the functions that exist and optimizing out those that don't. (Not that you would have noticed the overhead anyway, probably.)
- DSMan195276 11y agoI agree with you. Not all of this can be refactored into separate functions, but the parts that can't can be refactored to be much cleaner after you remove the #ifdef's made unneeded by the functions. Generally speaking, a lot of the cross-platform stuff in the Linux Kernel is handed this way, and done correctly there shouldn't be any over-head.
- x0x0 11y agoProbably with heavy code duplication though, as eg X clipboard management and X session management appear to be cross-cutting concerns. I mean, if you bury the ugly in just one function, I don't see how everyone is calling this horrid engineering. edit: I read this [1] and maybe the ugly isn't localized =P edit2: since you're reading this, thank you for ag. I use it every day. [1] http://geoff.greer.fm/2015/01/15/why-neovim-is-better-than-vim/ http://geoff.greer.fm/2015/01/15/why-neovim-is-better-than-v...
- to3m 11y agoThe obvious thing to start with is to get rid of MAY_LOOP and arrange things so there's always an infinite loop, and there's always a finished flag, and the finished flag just never gets set to FALSE in the cases where you don't want to loop. Now you've lost several #ifdef...#endif clauses, and there's no #ifdef nesting. One way of tidying up the inner parts a bit might be by splitting each FD handling code into an init part, and a part that checks for input and a part that checks for error. For example, here's the code for XSMP, whatever that is. This approach is pretty easy, because you can do it with copy and paste. That's exactly how I did it and that's how I can actually present you code: #ifdef USE_XSMP #define InitXSMP() \ if (xsmp_icefd != -1) \ { \ xsmp_idx = nfd; \ fds[nfd].fd = xsmp_icefd; \ fds[nfd].events = POLLIN; \ nfd++; \ } #define ShouldCheckXSMP() (xsmp_idx >= 0) #define IsXSMPInput() (xsmp_idx >= 0 && (fds[xsmp_idx].revents & POLLIN)) #define IsXSMPError() (xsmp_idx >= 0 && (fds[xsmp_idx].revents & POLLHUP)) #else #define InitXSMP() \ if (xsmp_icefd != -1) \ { \ FD_SET(xsmp_icefd, &rfds); \ FD_SET(xsmp_icefd, &efds); \ if (maxfd < xsmp_icefd) \ maxfd = xsmp_icefd; \ } #define ShouldCheckXSMP() (xsmp_icefd != -1) #define IsXSMPInput() (xsmp_icefd != -1 && FD_ISSET(xsmp_icefd, &efds)) #define IsXSMPError() (xsmp_icefd != -1 && FD_ISSET(xsmp_icefd, &rfds)) #endif #endif (You could argue about this - for example, should ShouldCheckXSMP() maybe always just be ``(xsmp_icefd!=-1)''? - but the way the code is written, this puts all the details in one place, and the logic in another.) Then the init code would have this bit: #ifdef USE_XSMP InitXSMP(); #endif And after your poll/select code - which you'd similarly hide in a function or a macro, which I've here assumed sets a flag called `any_events' to say that there were any events that might need looking at - you'd do the business like this: #ifdef USE_XSMP if (any_events && ShouldCheckXSMP()) { if (IsXSMPInput()) { busy = TRUE; xsmp_handle_requests(); busy = FALSE; if (--ret == 0) finished = FALSE; /* keep going if event was only one */ } else if (IsXSMPError()) { if (p_verbose > 0) verb_msg((char_u *)_("XSMP lost ICE connection")); xsmp_close(); if (--ret == 0) finished = FALSE; /* keep going if event was only one */ } } #endif (usual disclaimers for forum post code apply.) So: the actual logic is handled in one place, whether or not you're using poll and select, which woud be my key criticism of the code as it stands. And I don't mind having code like this in a #ifdef, if it's only one level deep, particularly if it's somewhat formulaic, which this function would end up being if you approached it this way. Then repeat for all the parts, and do a bit of work to declare the right variables at the top of the function (something I've just completely ignored). If you'd prefer to be able to step through it in your average debugger - which tends to do a poor job with #defines - you could do the above with functions, but you'd probably need to move all the state into a struct so that you could pass it around more easily. Perhaps you could have a mini wrapper for poll and select - for this sort of level of use I'd probably write something local to the file, since it's not so much a separate layer, or a library, or what have you, as just some little helper functions to stop the calling code becoming too awful. You could always have some kind of extensible function pointer-based system whereby a given descriptor has a callback to be invoked if its FD had an error or has input, which would give you the opportunity to have each subsection of the code supply a low-level function in its own file. (For example, say xsmp_icefd is global only because this function needs to use it - now it could be static to the xsmp support file, which would need only expose a function that would be called from here when input was available or there was an error.) And so on, and so on. I've worked on this sort of thing quite a lot over the years. There's always a way of doing things that doesn't involve a huge gnarly pile of nested #ifdefs and control structures inside #ifdefs. Either of those, let alone both together, are a good sign that you've taken a wrong turning somewhere. (Some people are doctrinaire about never including any platform-specific #ifdefs anywhere in the first place. I'm not - but those people definitely do have a point.)
- AdmiralAsshat 11y agoTo my knowledge, maintaining compatibility is one of the stated goals of Vim, even at the expense of performance. NeoVim is supposed to strip out some of these antiquated features.
- wyldfire 11y agoBut the ifdefs likely negate performance concerns for the most part. Decomposing this function into different implementations with appropriate abstraction doesn't need to break compatibility.
- austinl 11y agoAlso, it just so happens that the people working on NeoVim are currently porting all IO to libuv (the cross-platform library mentioned in the article). https://github.com/neovim/neovim#whats-being-worked-on-now https://github.com/neovim/neovim#whats-being-worked-on-now
- chronial 11y agoSee here: https://github.com/neovim/neovim/commit/4528046 https://github.com/neovim/neovim/commit/4528046
- carterehsmith 11y agoIt is a good goal for sure. That said, how does one go about submitting a "fix" for such a widely deployed software? Like, before submitting, I need to make sure it works on Amiga, VMS, Irix... and then all the current platforms. That is, like, a pretty high barrier... who in the world has all these platforms handy for testing? You submit a patch and someone says that it has a problem on Xenix 2.37.4 -- what do you do?
- ForHackernews 11y ago> who in the world has all these platforms handy for testing? This was the OpenBSD project's testing rack in 2009: http://www.openbsd.org/images/rack2009.jpg http://www.openbsd.org/images/rack2009.jpg
- erikb 11y agoTo answer most questions here: Yes, nowadays there are cross-platform libraries you can use instead of implementing that yourself. And yes code that has grown for centuries and contains unnecessary things or patterns that aren't used nowadays can be refactored. Or at least that's how I'd interpret the article.
- ProAm 11y agoI really dislike the code review witch hunts you see on HN (or anywhere). On one side of the coin you have startups that merely want to get something thrown together with duct tape, working and ship so they can refactor later and clean things up. On the other hand you have people writing blogs posts to humble brag their code reading and blogging ability. No one knows the circumstances that created this original code. The developer may have been working on 10 projects and threw something together just so it'd work. If it ain't broke....
- x0x0 11y agoA previous employer had a codebase that generated, on a full compilation, at least 10k warnings. That same codebase powered $200mm/year in revenue.
- omegaham 11y agoAnd if your developer time is better spent on producing more features than cleaning up your previously made code, you'll end up with 10.5k warnings. I'm sure that someone will freak out and cry, but as long as you can keep extending it and working with it, why fix it? Of course, technical debt builds up, and eventually you're badly locked in until you refactor, so it's a balancing act.
- erikb 11y agoTotally in for the balancing act. And additionally in an open source project it's possible to refactor for code beauty, because you can choose so for other reasons than resource management.
- Camillo 11y agoI'm a bit surprised that they have code like this: if (msec > 0 && ( # ifdef FEAT_XCLIPBOARD xterm_Shell != (Widget)0 # if defined(USE_XSMP) || defined(FEAT_MZSCHEME) || # endif # endif # ifdef USE_XSMP xsmp_icefd != -1 # ifdef FEAT_MZSCHEME || # endif # endif # ifdef FEAT_MZSCHEME (mzthreads_allowed() && p_mzq > 0) # endif )) When they could have written: if (msec > 0 && ( # ifdef FEAT_XCLIPBOARD xterm_Shell != (Widget)0 || # endif # ifdef USE_XSMP xsmp_icefd != -1 || # endif # ifdef FEAT_MZSCHEME (mzthreads_allowed() && p_mzq > 0) || # endif 0)) Perhaps they were targeting compilers so primitive that they could not optimize out a "|| 0". (edited to hide my shame)
- DSMan195276 11y agoA slight nit-pick, though I was going to say the exact same thing - `|| 0`. If you do `|| 1` the compiler's going to optimize the entire 'or' expression out ;) I was thinking that using `0` would cause a problem when you select none of those compilation options, but then I realize the code won't even compile if you don't select at-least one (You get empty parenthesis fallowing the '&&' in the 'if' statement), so it doesn't seem like a big deal.
- Camillo 11y agoThat's not a slight nit-pick, that's me being an idiot. I'm going to delete my account and travel the world barefoot for two years as penance.
- CephalopodMD 11y agoTry to code it, test it, and submit your request. This is why we open source.
- rasz_pl 11y agoI looked at the spaghetti in your post and assumed it was a joke .. but then I looked at the real code :(
- 11y ago
- jandrese 11y agoThis is a classic case of why legacy code is a nightmare to maintain. It's the OpenSSL situation all over again, and one can definitely see the appeal of going through there and ripping out all of the functionality that nobody uses anymore just to make maintenance less of a nightmare. Luckily vim doesn't run suid root on any sane system, so all of this legacy cruft is not as huge of a threat surface on the machine.
- zecho 11y agoYep. There's nothing worse that maintaining code that doesn't change, or rarely changes. All that doing nothing because the code works, or works well enough, to avoid anybody noticing it. Yes, that's the classic example of why legacy code is a nightmare to maintain. When I think of maintenance, I think of constantly refactoring things that work.
- joshstrange 11y agoWhile I see your point you are missing the point that Parent hits on: Maintenance. Sure if everything was working you wouldn't touch it but if you do need to make changes or add features at some point then having refactored it into something sane and readable makes a lot of sense. I doubt the Parent is suggesting we re-write everything just because it is old.
- kedean 11y agoIt is still an issue, since vi/vim gets used for sudo purposes all the time. Any time someone uses visudo to modify their sudoers file, for example, that's giving root privileges to vim.
- deleted 11y ago[deleted]
- kragen 11y agoWhen you visudo, you are subjecting vim to (1) your chosen input and (2) the contents of sudoers. If you are malicious, you could choose your input to be ":!", which gives you a root shell. If the contents of sudoers are malicious, they can give root access to whoever they want. So visudo is not a particularly dangerous scenario. Of course, it's possible that some aspect of vim will, say, create a temp file insecurely as root, or read random shit out of /proc, or what have you, and be exploitable. But the historical security problems in vim (and there have been several!) have mostly had to do with editing maliciously-composed files with it.
- gjkood 11y agoDoes this have a noticeable performance impact for a typical vim end user, using it in an interactive file editing workflow? On any modern hardware? I suppose there may be some negative performance impact if we need to use it for an automated/batch workflow (I can't think of many where something like 'sed' won't be better suited).
- joosters 11y agoBut the code works. It supports lots of platforms through choice. Yes, you could make the code prettier if you dropped some platforms. Yes, you could refactor it to use some abstracting libraries that now exist. But the code works. If you rewrote the code, the best result you could end up with is the same functionality that still works. All other possible results are bad. There is nothing to be gained.
- dustingetz 11y agoI wonder why didn't the vim folks write the abstracting library?
- amelius 11y agoSimple. Just imagine how this code evolved. First, they started with a simple 1-liner, that took at most 5 minutes to come up with. Then another platform was added, this took another 5 minutes, etc. Abstracting, however, would take perhaps a day of work. A full library such as libuv would have taken maybe a couple of weeks to develop. So there you are. QED.
- VLM 11y agoIf they added libvu support, we'd have a post about "VIM's 430 line keyboard input routine" instead of a mere 400. At least for a major release or so before they could flush the legacy code. If they can.
- jsprogrammer 11y ago>There is nothing to be gained. What about easier extensibility? Not many are going to want to look at that code, let alone try to add some additional functionality to it.
- chadgeidel 11y agoI am reminded of the old Joel on Software article "Things you should never do part 1": http://www.joelonsoftware.com/articles/fog0000000069.html http://www.joelonsoftware.com/articles/fog0000000069.html From the article: "The idea that new code is better than old is patently absurd. Old code has been used. It has been tested. Lots of bugs have been found, and they've been fixed. There's nothing wrong with it. It doesn't acquire bugs just by sitting around on your hard drive." EDIT: Joel isn't actually recommending "do nothing" - on the contrary - the article goes into some depth on ways one can improve software without throwing everything away and starting from scratch.
- kosma 11y agoThere's a deeper underlying problem: the bit of code lacks any architecture. Even though libuv and others didn't exist back then, that's no excuse to just pull random descriptors from various parts of the program and stuff them in a select, repeating variants of the same logic over and over. Even creating a consistent notification/callback interface would make the code much more readable, as the underlying pattern is always the same: watch a descriptors and call a function when an event occurs. It's just lazy and ugly.
- stuartaxelowen 11y agoYour solution sounds like Enterprise Java to me - instead of understanding one long simple solution, you have to understand 3 shorter, less simple solutions.
- falcolas 11y agoHow much would that have cost in speed 10, 20 years ago? Function calls aren't free, and their cost was pretty high before Moore's Law all but erased it.
- MBlume 11y agoI'd like to see what the code looks like after it's been through the preprocessor in a modern Linux environment -- I'm guessing a hell of a lot shorter?
- mkagenius 11y agoCan't believe people are going mad over a code snippet when they don't know under what coditions they were written and under what coditions the code base is being maintained.
- cat_dev_null 11y agoIf you are all such experts, why don't you "fix it" and then pull request it in.
- knieveltech 11y agoThere it is right there.
- brandonwamboldt 11y agoPlease, you can critique something even if you lack the skills to fix it, or the desire to fix it, or the time to fix it. Also, you can point out that something is broken even if you have no suggestions on how to fix it.
- tastynacho 11y agoYou can do whatever you like, but if you were raised right than you'd understand his point. Criticizing something that is broken with no desire/ability/whatever to fix just makes you look like a douche. If you can't do anything about it keep it to yourself; you're just wasting time otherwise.
- adrusi 11y agoWow that's rude. No need to insult someone's upbringing on a thread based on their musings about a snippet of code. Also you're wrong. Critique is useful in and of itself, not just as a direct means to getting something fixed. If person A doesn't have the time/skill to fix something, they can critique it, hope that person B sees the critique and goes on to fix it. Also, by critiquing it, it starts a discussion about what caused the problem, and how it might be fixed, which is useful for third parties reading the critique: now they know what not to do in their own code. If you're censoring all of your criticisms just because you don't have the resources to execute on your own, you're hindering discussion and doing a disservice to the community. In a way you're bikeshedding. Imagine if you were at a coffeeshop and the barista makes a racist remark about the customer in front of you. Do you sit there quietly and let it happen just because you don't have the power to fire him? Or maybe a less loaded example: suppose your friend gets scammed into paying $2000 for a $900 laptop, do you tell him? Doing so might make him feel stupid, but if you care for his well being you'll tell him so that he doesn't do the same thing again. Criticism isn't rude, it's useful. Insulting someone based on two sentences they post on the internet isn't useful, it's rude.
- aceperry 11y agoFirst glance at the headline had me wondering, "Is this a good thing?"
- vmorgulis 11y agoncurse is similar with a lot of legacy code to support old terminals.
- PSeitz 11y agoDo one thing and do it well
- thebelal 11y agoFor those interested in viewing this code in context is is at (https://github.com/vim/vim/blob/db9bc0b7931d252cf578c1cd298ac905b904ebe7/src/os_unix.c#L5203-L5624 https://github.com/vim/vim/blob/db9bc0b7931d252cf578c1cd298a...) Also note that RealWaitForChar has been completely removed from neovim since April of 2014 (https://github.com/neovim/neovim/pull/474/files https://github.com/neovim/neovim/pull/474/files)
- breadbox 11y agoThere is nothing wrong with supporting lots of platforms, but those #ifdefs need to be encapsulated in wrappers functions (or macros). This is a classic example of premature optimization, actually. You use one or two #ifdefs directly because you hate to pay the cost of function overhead just to make the code easier to read. (Even though there's practically no point in tiny optimizations just before the code is going to wait for keyboard input.) A few years go buy, a few more situations are done via #ifdef because at least that way it's consistent. Eventually you have a nightmare function like this, where reading it forces you to read every possible version of the function simultaneously. Encapsulate your #ifdefs people!
- wyldfire 11y agoOr don't use them at all. For where the behavior must be different, create different source files with the same function signature. When building, link only with the implementation appropriate for the target being built.
- userbinator 11y agoYou can easily skip over the #ifdefs - they're all very short. IMHO I'd rather scroll over code I'm not interested in, than have to jump around to figure out what really happens if they are defined.
- yoklov 11y agoI don't think this was done for the purpose of optimization. Usually this happens when you want to add support for one small change, and its easier to get a small patch in vs a big one. Its not really the classic case of premature optimization either. At least not in my experience. That's more like 'I know I need a spatial partition here, time to research all the ways they can be implemented and their performance tradoffs, and implement a really good one" when you should have just used a hash table and done the other stuff if spatial lookups even show up when profiling. Stuff like this is way more damaging for both codebase complexity and productivity then anything else. The golden rule is to only do enough optimization to make it easy to do the optimizations you might need to do later, but no more.
- mrbill 11y agoSpeaking of legacy platforms, anyone know of a vi/tinyvi/etc work-alike for CP/M? I'm going to be doing some hacking on z80 assembly via Yaze, and it would be great if I could have the editor I'm used to, natively on the platform (rather than having to edit in OSX or whatever).
- daxfohl 11y agoSo when will 16K be a standard resolution?
- rootbear 11y agoI assume portability is why the function declaration is old K&R style and not ANSI prototype style. I'm always surprised when I see K&R style in modern(ish) code. I do miss the ability to declare multiple parameters of the same type without repeating the type name, though. Oddly, several modern languages (like D) seem to think that's a feature.
- glass- 11y agoCheck vim's style guide (:help style-example in vim), you'll find a note that says: > NOTE: Don't use ANSI style function declarations. A few people still have to use a compiler that doesn't support it.
- rootbear 11y agoAmazing. I wonder what platforms those are.
- Artemis2 11y ago> I do miss the ability to declare multiple parameters of the same type without repeating the type name It's a feature Go has!
- rootbear 11y agoYes! I was pleased to see that.
- manis404 11y agoReally, why does Vim still exists in the first place?
- rando3826 11y agoEmacs C code is far better! And it's only ~22% c code instead of vim's ~66% reference: https://www.openhub.net/p/vim https://www.openhub.net/p/vim https://www.openhub.net/p/emacs https://www.openhub.net/p/emacs
- brudgers 11y agoVim or Emacs, either is fine. So is Eclipse. Etc.
- wtbob 11y ago> Vim or Emacs, either is fine. True enough. > So is Eclipse. No, Eclipse must be killed with fire.
- pixelbeat 11y agoNote Emacs uses http://git.sv.gnu.org/gitweb/?p=gnulib.git http://git.sv.gnu.org/gitweb/?p=gnulib.git to abstract away platforms differences
- saosebastiao 11y agoI would much prefer the coeffect system for managing different platforms and capabilities: http://tomasp.net/blog/2014/why-coeffects-matter/ http://tomasp.net/blog/2014/why-coeffects-matter/ It would be so amazing to be able to take all of those ifdefs and turn them into type variants and have the compiler enforce the safety and semantics of the system. And it would be phenomenal for old code to break at compile time when the environment changes, instead of waiting for a bug report to roll in. So, paging T. Petricek...when are we gonna get it in F#? :) Even better if someone can get it into Rust! That is the perfect type of feature for a systems programming language.
- kyberias 11y agoI don't see any Amiga specific code here.
- riquito 11y agoI've just realized that Vim never exited with an error in my whole life, while pretty much all the other editors I've ever used did. While his code is old, it's certainly resilient.
- michaelmcmillan 11y agoOpen Vim. Type "1.02". Put the cursor on the 2. Hit C-x; get 1.01. Again; get 1.00. Again; get 1.01777777777777777777777. - Gary Bernhardt (@garybernhardt)
- jerf 11y agoIt would be interesting to run this through the preprocessor and see what it comes out as on a real Linux system or something. I can't really tell through all the #ifs, but it would certainly be much shorter.
- dale-cooper 11y agoAnother "interesting" project to look at is nethack.
- noobermin 11y agoTo be very frank, I've seen much worse. "Functions" more than 400 lines long, perhaps even 1000 or more, riddled with more macros like in this sample than you can shake a stick at. I'd share a sample of this ghastly stuff, but it's closed source, alas.
- andrewchambers 11y agoifdefs inside functions create monstrosities, it is far better to have few preprocessor conditionals, and instead have platform specific c files.
- throwaway3648 11y agoJust getting window resizing across curses implementations took me 200 lines of C
- amadeus 11y agoYet another Vim bashing post by the Floobits bros. It's getting old.
- kelvin0 11y agoEMACs also does this with a VM made from a DSL written in LISP. Of course, I never use either VIM or EMACS ... I am mostly in VS land 99% of my time. I can't even try to imagine what THAT code most look like.
- jcl 11y agoThis reminds me of a talk at last year's CppCon about modernizing legacy code. In it, they talked about a core output function of the MSVC standard library that had accreted enough #ifdefs over the years that the function signature alone spanned over 100 lines. It's a great example of how repeatedly making the minimal necessary change can drive code into an unmaintainable mess. When the team found that the function was impossible to modify to accommodate C99 format string changes, they undertook a lengthy project to factor out the #ifdef'd features using abstractions available in C++. Not only were they able to turn the code into something much easier to modify, but they also fixed multiple hidden performance bottlenecks, so the end result actually ran 5x faster than the C version. https://youtu.be/LDxAgMe6D18?t=69 https://youtu.be/LDxAgMe6D18?t=69
- firebones 11y agoIt's also a case where making that investment is worth it given the core nature of the MSVC standard library which makes it integral to a universe of other software. The global impact of a 5x improvement in something in every app makes it a no-brainer. But there's a lot of debt out there that will be replaced before the payoff ever comes. Interesting Fermi problem for sadistic interviewers: what would be the global energy saving per invocation of this vim function if a 5x performance improvement were to be found?
- jhallenworld 11y agoJOE never tries to use poll or select (it uses multiple sub-processes writing to the same pipe to implement input multiplexing). This archaic way works on all version of UNIX, even very old ones which don't have select() or poll(). No #ifdefs needed :-) Output processing in JOE is interesting: when writing to the terminal, JOE periodically sleeps for a time based on the baud rate and amount of data. This is to prevent too much output buffering so that at low baud rates you can interrupt the screen refresh with type-ahead. If you don't do this at 1200 baud it's a big issue (you could wait for hours if you hit PageDown too many times).
- hackuser 11y agoI wonder how many examples there are of a more beloved UI (among coders) than Vim's keyboard input. For myself, its exceptional keyboard responsiveness is a essential part of what makes Vim feel so effortless, so hardwired to my brain. I wish all code was equally buggy.
- jheriko 11y agothere is no excuse for this. its trivially refactorable into something easier to maintain with less ifdefs if you are willing to include/exclude files by platform. (and if not, just wrap whole file contents in single ifdefs) this is a monster that has grown over time without any proper love.
- lnanek2 11y agoIt's ugly, but vim is one of the very few programs I've always seen ready and available on any machine I log into. Even the login shell used/available changes, but vim is always there. So they are doing something right.
- fibo 11y agoIf I use vi, vim or neovim as a user I eill not look at the code first, I will look at availability. If I am working on a RedHat server for a customer of mine I will use vi cause it is already installed.
- reilly3000 11y agoWhat are some examples of open-source project that are in daily use by millions of folks that don't have some spaghetti code? I am sure there are some out there, but I really can't think of any at the moment.
- Spakman 11y agoI suppose it's because I've spent quite a lot of time in the GNU Readline source that this function doesn't seem that bad. Not that I'm wanting to endorse it as great code, of course. I find it fascinating to look at how old but very well used software develops (often, but not always) in ways that seem completely ghastly.
- renox 11y ago> Vim tries to be compatible with every OS, including dead ones such as BeOS, VMS, and Amiga. There are people working on BeOS revival: Haiku OS, they would (rightfully) quite annoyed if vim dropped support for the OS they're trying to resurrect..