CodePerfect 95 – A fast IDE for Go
codeperfect95.com
codeperfect95.com
https://github.com/visualfc/liteide/releases
It's actively developed, FOSS (LGPL), native C++ (Qt), runs on Windows/macOS/Linux, supports go.mod, and uses gocode/gotools for intellisense instead of gopls. It has integrated debugging, go to definition/usages, and some refactoring support.
I hope for Linux version soon.
That being said, not a fan of a monthly subscription for a native desktop application.
I'd be willing to pay $5/month for a beta version, if I were using windows. Or alternatively, if someone is watching, I'd be willing to pay $5 for a trial of a mac version :) Respect it's quite a bit of work to support a second OS and window manager and you have to start somewhere - Hope it goes well and makes its way over to Mac soon!
Why should I pay $5/month for this instead of just coughing up the cash for CLIon? Or, better yet, why wouldn't I just save that money for a year or two and buy a GPU for smoother scrolling? I love lightweight software, but this seems like putting the cart before the horse on so many levels...
You're also competing with the LiteIDE. It's free, light as hell, and as far as I can tell does everything this does probably as lightly as this does.
Beyond that, I'm sure for the thousandth time you've heard it "why does everything need to be a service these days?" Har har, but seriously why not give this a reasonable 1995 pricing model if you're playing up the 95 angle for Christ's sake.
60 bucks per year for a language specific IDE which has multiple competitors with more features just doesn't seem like that good of a deal. Others have pointed out LiteIDE, which is open source and doesn't cost anything.
That's probably the biggest annoyance. There are a ton of other minor ones, too.
To be fair, language servers in general are absolute garbage, but the combination of VSCode and gopls is particularly bad.
Sure do whatever. I'll just ignore the product. I really do not care about this "valid for continuous usage". You do what suits you and I do what suits me.
I STILL get the odd $0.23 subscription charge for some AWS thing I haven't used in a decade, and I can't figure out where it's even coming from.
I have also canceled an aws account over this which I would not recommend as they require you to go through support to reactivate. Doable but annoying.
Jokes (not really) aside, why does an IDE need to be designed for a language anyway?
I feel this is somewhat related to the fact that noöne has figured out how to do extensible widget toolkits or scene graphs either. (Yes, Electron does in fact solve an actual problem, if in a profoundly unsatisfying way.) Actually, just a text input box that could handle the complexities of the world’s writing systems (RTL, complex font shaping, arbitrary input methods, autocorrect, all that with at least one cursor or selection) and was capable of supporting the facts vs rumors approach from FRP[1] would be a significant advancement re toolkits. As for scene graphs, I don’t actually know of any viable general approaches to assembling an interface out of independent parts (that doesn’t work by presupposing a large substrate of features in the host “shell” and providing a separate extension point for each of shortcut, menu item, toolbar button, sidebar, dialog, ...).
Actually, now that I’ve written all of that out, it seems that another way to put my second point is that the language-agnostic IDE problem is a proper superset of the composable GUIs problem, and nobody knows how to solve that one. Composable CLIs are easy—they’re called “[textual] programming”; but then composable GUIs (or TUIs, the graphics/text distinction is immaterial here) would seem to correspond to visual programming, and last I checked the latter still sucked.
[1]: https://apfelmus.nfshost.com/blog/2012/03/29-frp-three-princ... [2]: http://acme.cat-v.org/
Rob Pike did. Acme is absurdly simple yet absurdly powerful. Because everything is text and any piece of text is executable. Combined with the plumber[0] it beats every other approach to extensibility that I've seen. You can have any "IDE-ish feature" with a plumber rule. And you don't lose simplicity.
> Emacs is probably the simplest language-agnostic IDE.
No. See above.
[0]: http://doc.cat-v.org/plan_9/4th_edition/papers/plumb and https://9p.io/wiki/plan9/Using_plumbing/index.html (also, Russ Cox has made a great demo video, it's on YouTube)
OK, so what are the things that, to me, differentiate an IDE from “just” a programmer’s editor (mind you, I usually use the latter) but don’t seem to have an obvious solution in Acme?
- File tree with interactively collapsible subtrees (although this is not really an IDE feature, even Gedit has one). Haven’t seen an implementation, and don’t really see how one could fit into the UI paradigm without being awkward (would I have to select “collapse foo” to collapse the foo/ subtree? I’d much prefer to just click on foo).
- Jump to definition and list uses, using semantic analysis and not just text search. The former should be doable with plumbing but I don’t remember it described anywhere; the latter should be dead easy using something like cscope, but again, I haven’t seen an implementation, and also the interface would have to be a list of all matches and not in-file highlights, which is sometimes what you want and sometimes not.
- Rename identifier, again preferably non-dumb. Sure you can call out to a separate CLI tool if you don’t mind the lack of interactive feedback, but given the brilliant handling (theory, really) of multiple selections in Sam, I’m really frustrated Acme not only can’t accept multiple selection ranges from an external program, but doesn’t seem to support multiple selections at all.
- Autocompletion. While it is admittedly not essential for programming under Plan 9 (and that’s a good thing), in other environments unfamilliar libraries or horribly large APIs (looking at you, Google Apps Script) make it a necessity. As far as I can see, impossible to implement without forcing the programmer to take their hands off the keyboard.
- Debugger integration, or at least navigation through source files as the debugger steps through the program (showing variable values from the stack is good but optional). Should be implementable with a cooperating debugger, but once again not actually implemented as far as I’ve seen, and the lack of any way to highlight the current line will make it a bit unwieldy.
- VCS integration, at least a way to do `git add --interactive` (or equivalent) without going through a hundred questions in the terminal. Doesn’t really fit into how the UI works, unless I’m simply forced to edit patches manually. Even simply highlighting the dirty lines while editing would be tremendously useful, but the UI still can’t highlight lines.
- Syntax highlighting (yes, I went there). While you can indeed do without the classic syntax highlighting many people use, what I find helpful about it (even if I have to write my own syntax files) is that it can quickly highlight obvious syntactic programs that can result in pages of awful compiler spew: runaway strings, unbalanced parens inside a(n explicitly terminated) statement, etc. Jump to or highlight matching parenthesis is useful for the same reason, but I don’t consider it a must.
That’s a lot. Some of those things are possible, and many are, irritatingly, almost possible but not quite. But even if the UI admitted all of them, none of the tools that would implement them actually exist. Thus I conclude(d) that Acme is not a functional IDE, and while it is a good advance towards a more elegant “shell” (as GP called it) for one, the UI model is just a tad too restrictive in multiple directions. I suspect that trying to expand it in all of those directions, however, will ruin the elegance.
Just to be clear, this rant (I can’t seem to be able to produce anything else) is not an anti-Acme rant. Its point is not that Acme is a bad editor (it probably isn’t, it’s just that I can’t get the control scheme to click for me). Its point is that it is not a solution to the IDE bloat problem because it’s not an IDE. Perhaps we shouldn’t be solving the IDE bloat problem at all and just give up on the idea; but supposing that we want to, I don’t see how Acme accomplishes that.
P.S. I don’t use Emacs regularly either, but curiously the things for which I have used it in the past—Org mode, Agda mode, Paredit, and of course Dired—use its flexibility in such an essential way that not only are they impossible to implement atop Acme, they are probably impossible to do on top of the code editing widget in any other extensible editor except those that implement essentially the same ideology (Climacs, Edwin, et al.).
As much as I also love the The New Yorker diaeresis, “no one” is two words, not one, so no need for one here.
Then I looked it up, and it turns out that both “no one” and “no-one” are accepted spellings for this linguistic gadget while “noone” is rejected by prescriptivists as a confusing spelling because of the double “o”, even if it would be in line with “everyone” etc. “Noöne” is admittedly funky and nonstandard, but if the no-diaeresis concatenated version is rejected because it’s confusing (though come on English, your whole spelling is nuts, why are you so stubborn on this one), then the diaeresis version should be completely acceptable.
That's the party line. In reality Go users have adopted GoLand just fine for example...
People want their IDE to do all the ancillary tasks, and Go builds most of these into the core, so it's a good first target. You can be "feature complete" without complexity.
Consider the case of a C++ IDE. Which compiler do you support; gcc, clang, msvc? Which build system do you support; Bazel, make, cmake, gyp, autotools? Which C++ standard version does the syntax highlighter support; can you change it per-project? If you do change it per-project, how do you configure this?
If you pick some opinionated subset, your userbase is 0 people. If you support everything people want, you have 30 people working on it for 10 years and you still fail.
For me, the killer feature of any IDE has always been integrated debugging and able to inspect the data. Integrated testing has also been another feature I cannot live without today.
I had to run a 4k screen through an adapter that could only do 30hz@4k and it was a horrible experience - I could notice the lag even when I was typing and scrolling anything was stuttering. I feel like my eyes got tired faster working on that screen. Why would you use that as a main display ?
30hz is on the realms of possible unnecessary eye damage in the long run.
I also grew up on CRT monitors, they probably did the most damage...
That said, it's certainly not for watching video or playing games.
I have a 360Hz monitor and it is really amazing what the reduction in input latency feels like in the real world. All of this input lag that gets blamed on USB or bad input subsystems is really just double-buffered vsync.
Having everything visible at once is a big plus.
Today, I just assume a beta launch will work on a Mac.
In the last few years, it seems Microsoft has done a great job with features like WSL on Windows.
So is this a sign that Windows is regaining mindshare?
Yeah... probably reading too much into this...
Small and short-lived class instances (more ideally structs) are the key to success with low-latency applications in most GC'd languages. If you are only touching gen0/1 in a .NET5 app, you will probably find the GC impact to UI latency to be negligible. In .NET, avoiding gen2 allocations is pretty easy. The biggest thing is replacing every byte[] with Stream as feasible, so you don't send objects directly to LOH (gen2). I believe the LOH threshold for byte[] is lower than the published limit of 85k, but I cannot recall the specifics (might be closer to 10k). Regardless, you really shouldn't be holding onto chunks of memory that large if you can ever avoid it. In some cases you can cheat. Pass around the path/id to a file and then stream it from disk at the very last possible moment (i.e. copy a FileStream direct to the HttpContext.Response.Body stream). If you absolutely must allocate large objects, try to reuse them as much as possible. Act as if anything entering gen2 is in memory forever, because with enough LOH fragmentation, it might as well be.
UI is one thing, but real-time process control is a wholly different animal. If you want to write a PID in a GC language, you better be prepared to eschew any notion of allocation in the process under collection. Even if you don't allocate, there are runtime components that still will, so you will almost always have some minimum amount of noise to contend with. That said, if you only need to run a PID loop at ~10khz (100uS loop delay), you probably wont have any issues. Just make sure you put the PID loop on a high-priority thread and care for its surroundings gingerly. A Raspi4+ is actually an amazing platform for this sort of thing.
Like C#, Go has value types, so controlling allocations should be pretty straightforward.
I could imagine plenty of other reasons to go with C++ though - there's still going to be a higher performance ceiling, maybe they plan to support languages other than Go, maybe they want a minimal file size compiling to WASM or to use specific C++ libraries etc. It would be interesting to see the original author's thinking behind it, on the website it's mainly comparing C++ to web technologies.
Lol.
" 30% of CPU cycles were being spent in function calls related to GC. " https://blog.twitch.tv/en/2019/04/10/go-memory-ballast-how-i...
You do have to watch out for the case where you can't use all the cores, and GC is blocking actual computation the user wants to perform.
(Also, you're at about 4000 cores when saving 30% buys you another developer. So you have to think about when the right time to unlock that money is, and how much it costs to unlock.)
I've been writing a game in Go. The GC doesn't prevent me from getting a smooth 360 frames per second. 1ms is a substantial pause, but isn't even a missed frame.
Especially considering that text editor state changes are dependent on user interaction—it’s not like a video games where the state changes continuously.
I'd wager the biggest hurdle to writing an IDE in Go isn't the language but rather the lack of mature graphics library bindings. I've seen some attempts at building GUI toolkits in Go but it's fair to say the language's strong points are still firmly in CLI and backend web development domains.
Text editors, especially with language aware features, are far from simple.
A frame drop causes little more hazard than just an unhappy gamer.
Speaking of which, many keep forgetting that Unreal C++ and Blueprint make use of GC.
In places where you have to use reference types, sometimes you can allocate everything you should ever need up-front and then pull from that pool of pinned instances throughout the day. Pre-allocating all of your required memory can provide more deterministic outcomes.
The JVM does have a “do nothing GC” for short lived apps, where not collecting is ok.
In .NET you can also change the GC policy at the thread level which can help a lot.
Pool Allocation (long held chunks of memory that can be manually repurposed) can help a lot, since you can write custom Pools where the Gc never knows it needs to clean up. It is a useful tool when you have big chunks of memory that need to be manipulated at a high rates.
I would say from experience that 500Hz-1kHz is a more reasonable loop time
So, Perl is obviously a much better language. Except that it turns out it's a lot easier to write Perl itself (the interpreter) in C than to write it in Perl. So Perl is better, because it's better for "writing C", and C is better, because it's better for "writing Perl".
The irony is still funny, but it is clearly based on a feeling that language goodness is one-dimensional, even when we know that any comparison of hammer and saw on a single dimension is going to miss most of what matters.
The approach there was just to ingest a long book from Project Gutenberg, record all of the trigrams (including across word boundaries), and disqualify a candidate plaintext if it had more than some low number (3, but it was a short text) of unrecognized trigrams. This worked beautifully.
For reasons I don't recall, I wrote the assignment in C. I didn't want to do the parsing of the book into a trigram table in C. So I did that separately, and emitted C code to assign to a three-dimensional character array for every trigram I found. Then my assignment was the concatenation of some code initializing the array to zeros, the emitted code adding ones to it, and, thousands of lines later, the actual decryption code.
WordPerfect was a huge monster, probably one of the largest (15+ diskettes) and sluggishiest DOS apps I had back in the day.
Windows 95 was cool, but also a significant step back on snappiness compared to 3.11 or even OS/2 Warp.
There are probably much better retro-snappy names, like, don't know, CodeKick 1-2-3?
Hmmm, I don't remember it being sluggish. I worked at the university computer lab at the time and remember WP being of of the snappiest programs. It was mostly written in assembly till the later versions.
My pattern matching brain: This usually means missing functionality present in competitors, or a comparison to things not reputed for their speed.
Microsoft used to maintain a log inspector [1] which you could use to see the chatter between the server and client, and there was a _lot_ of chatter with a _lot_ of JSON.
[0] https://microsoft.github.io/language-server-protocol/overvie...
[1] https://github.com/microsoft/language-server-protocol-inspec...
If someone has all their CPU fans, etc. spinning up when opening a big monorepo it's probably just aggressive indexing inside the LSP server they're using. Almost certainly it's an optimization trade-off made by the LSP server author, trying to balance the common case of people typically opening smaller repos and assuming they immediately want search, etc. to be fast and ready.
There's nothing inherent to the LSP protocol or design that causes this problem--someone could build a better LSP server designed to handle large monorepos by deferring indexing, etc. until absolutely needed (but potentially with some tradeoffs like searching inside a subunit being delayed until its used). It's the same basic problem git faced with enormous repos over time slowing down and all the hacks/workarounds people have bolted on to try to limit how much of the monorepo state needs to be available at any moment.
Even though most of the indexing and intellisense features are done within the language server itself, there'd still be significant overhead in JSON parsing and serialisation right?
The response example for the `textDocument/definition` request [0] shows a very large snippet of JSON considering the information it conveys:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"uri": "file:///p%3A/mseng/VSCode/Playgrounds/cpp/provide.cpp",
"range": {
"start": {
"line": 0,
"character": 4
},
"end": {
"line": 0,
"character": 11
}
}
}
}
[0] https://microsoft.github.io/language-server-protocol/overvie...Goland doesn't have any of these issues. Whatever they did, it works.
Ah yes, such a winning way of referring to people who like a different text editor to you. Way to up the quality of discourse.
1. https://springframework.guru/gang-of-four-design-patterns/
Looking at 27:41 [1] I can hear maybe 12 key strokes to add some closing parentheses. It adds an extra newline that the programmer has to delete by hand.
I'll never add nonfree tools to my edit/build/run toolchain, however. Every single piece must be fully and freely user-modifiable. These are my work tools.
They talk about vim support being first-class in their app. Well, vim is free software, so if you're not, you're not really vim-compatible.
Madness? gopls in particular works great now.
With all respect - I don't really see why would you you need a separate IDE when you can have nvim with native lsp + gopls. Or vscode\goland if you'd rather have an out-of-the-box solution.
Goland can be slow and laggy at times but this is the price for all those things baked into it (if you need them).
I mean - why not just use Vim then? What am I missing? Also the fact that they are selling "auto format" as a feature for a go IDE is... puzzling.
Some day I will get angry enough and I'll have to make it myself.
okay, that was just plain cool!
FWIW, I use lite (https://github.com/rxi/lite) if I need a very lightweight text editor that has rust linting (https://github.com/liquidev/lintplus) and Idea if I'm at my desktop.
It doesn't have nearly as big a community behind it, so adjusting your tooling can take time, but I'm doing mostly Rust these days and it does a fine job for me. That all might be a dealbreaker for some, though. I do know Elm support was way better in Atom, but I'm not writing that very much these days.
You will lose a lot of potential customers, which can kill your product especially if you're a very small entity.
Subscriptions are working for Adobe. As much as I dislike subscriptions the writing is on the wall. I wouldn't create a new non-subscription product now.
Anyway, to each their own..
However, I'm on a mac.
I understand that it's not done yet, but an option to subscribe to a mailing list or a news letter so that I'm informed when the mac version comes out would be nice.
No, it was dog slow to start because rotary I/O was slower than a snail, but once the sw got loaded, the input and feedback was instantaneous.
It's actually copying vim's keyboard mappings, so you know it'll be strictly worse than vim, which, again, is free.
Also I can't take its "zero lag" claim seriously if it says vim is fast. Try opening a 10 MB XML file in vim with syntax highlighting on and see if you can spot the lag.
I'm not convinced why I should even spend time investigating this.
...
> The IDE is very much unfinished. ... it freezes when opening super huge directories.
So here's what's likely to happen:
1. To fix that freeze, you realize that you need to do file loading asynchronously in the background.
2. That in turn means you need to have your parsing/analysis run asynchronously so that it can analyze files as they come in.
3. But the UI that is reading analysis results is still running on the main thread. So now you need to add locking and other concurrency stuff everywhere. This takes a year of your life. At the end, your IDE is now twice as slow.
4. Also, the user still wants to be able to edit code while all this asynchrony is going on. (Otherwise, you'd just freeze like you were before.) So now your analysis engine needs to handle both concurrent reads and writes while also doing file IO.
5. At this point (especially with all that locking and other concurrency stuff), it's so complex that "re-analyze the entire program from scratch every time" is too slow. You need to be able to maintain a persistent analysis state and incrementally update as the user changes code or files get reloaded. You build a complex dependency graph system so that you can determine which analysis state must be invalidated when a line of code in one file is changed. This is another year of your life.
6. Now your analysis engine is so complex that the limiting factor for making your IDE better is developer productivity. It is incredibly hard to touch this giant ball of mutable concurrent incrementally updated state without breaking something and/or losing your sanity.
7. You eventually realize you need to architect it at a higher level. Instead of low-level threading and locking and carefully hand-authored incremental updating code (which few humans can maintain), you replace it all with a bunch of more coarse-grained persistent data structures. This takes a couple more years of your life. At the end, you get an analysis engine that you can maintain, which is good, because in the meantime, three new major versions of Go have come out and users asking you to support 17 other programming languages. But your new coarse-grained analysis engine is five times slower than the old ball of spaghetti...
8. A user files a bug saying that the IDE crashes when they try to open their 20-million line Go program. It turns out your implementation assumed you could always fit the full AST for every source file in memory. OK, time to start working on a compressed code representation....
9. Meanwhile, another user files an innocuous little bug asking why the editor doesn't support full-width characters, right-to-left languages, or emoji. You open up your beautiful, 200-line hand-written fixed-width text renderer in one tab. Then you open the Unicode spec in the other and start reading about "extended grapheme clusters", "combining characters", etc. In a third, you start reading about OpenType "multi-colored glyphs"...
I agree that IDEs could be faster than they are. There is a lot of cruft. But it's very hard to fix that by starting with OpenGL Notepad and hacking your way to IntelliJ one Git commit at a time without ever monotonically regressing perf. That's like trying to solve climate change by taking a tricycle and incrementally welding your way to a carbon-neutral container ship.
Writing a real-time code analysis engine for large-scale programs is hard. It's a big complex piece of code. Comparing it to a text editor is like comparing Tetris to World of Warcraft because they're both "games".
That being said, I completely applaud the author for making a go at it. It's hard, but not impossible, and history is written by people who had the courage to do hard things.
10. You get a request for accessibility support, because a whole team uses your lean and mean IDE, and now they want to hire a blind person. Now you get to learn about the hard-to-implement UI Automation API for Windows (disclosure: I was on the Windows accessibility team at Microsoft), or its counterparts on other platforms.
I'm planning to work on an abstraction over those platform accessibility APIs. Think of it as the GLFW or SDL of accessibility. Hopefully the kind of developer that tries to fight bloat by implementing their UI from the ground up will be willing to bend a little on this point.
But that does not stop people using it for desktop apps. (same with PHP and JS)
But is that really a good idea?