« So much for Twitter | Home | Curses, foiled again »

Fixing the JED dealbreakers

Sat 4 Sep 2010 by mskala Tags used: , ,

There are many things I like about the JED text editor, and for a number of years it has been my preferred editor for working on C code. However, it has a number of misfeatures that make it unacceptable for other tasks for which I need a text editor, so I have generally been using JED only for C code, and JOE for most other things (including, notably, English-language writing of both fiction and nonfiction in LaTeX and flat text). Just recently I had occasion to try to edit some C code on my laptop, which had a fresh default installation of JED, and it was a horrible experience, and I realized that I had, years ago, made a number of customizations to JED that I'd long since forgotten about.

For my own future reference, and anyone who might be facing a similar situation, here are some notes on changes I made. I decided while I was at it to try to not only bring the laptop's installation up to the desktop's standard so I could use it for C, but also fix as many as possible of the issues keeping me from using JED for other things on both installations, so that I could at least consider adopting it as my general editor instead of mostly using JOE. It remains to be seen whether JED will be able to serve as my all-purpose editor, but so far I've been liking it once I sorted out these issues.

Indentation and C_BRA_NEWLINE

JED attempts to understand enough of C's syntax to do nice indentation automatically. You can move the cursor to a line, press tab, and it will automatically add or subtract whitespace to put the line where it should be. This in itself is a really nice feature that I like and want; it's probably the major reason I've been using JED for C despite using JOE for almost everything else.

However, it has several modes for what indentation style you want, and in most of the modes, there is a feature enabled called C_BRA_NEWLINE, which attempts to enforce a rule that every opening brace must be on a line by itself. If you type "if (a==b) {" then what you get is a newline inserted right before the brace, to put it on a line by itself.

The inserted newline is a jarring interruption in the user experience; you're typing away and all of a sudden you're on another line at a different indentation level because the machine has decided to do something by itself that you did not tell it to do. Jarring interruptions in general are something users violently hate; the Dancing Paperclip was hated for exactly that reason. The indentation style that puts braces on lines by themselves is also a serious problem, especially on my laptop where there's a shortage of vertical space on the screen, but I could live with a less than perfect indentation style as long as it was sort of close and there were no jarring interruptions while I was typing. One of the several indentation styles JED offers turns C_BRA_NEWLINE off, but I dislike that style for other reasons - it uses too much horizontal whitespace, making it difficult to keep code within 80 columns where it should be. Ideally, I would like to configure JED to its own default indentation style, which I like in all other ways, except with C_BRA_NEWLINE turned off and opening braces on the same lines as their introducing keywords. That's how my desktop computer's JED has been configured for years, and until the last few days, I'd forgotten I had even done that let alone how.

It might seem logical that one could put "c_set_style ("jed"); C_BRA_NEWLINE = 0;" in the .jedrc file to select JED's default indentation style with C_BRA_NEWLINE turned off.

That doesn't work. The C_BRA_NEWLINE variable ends up set to 1 (as you can verify with the variable inspector within the editor) even though that code appears to be perfectly correct S-Lang syntax. It is the same syntax shown in the documentation. You can change many other variables that control JED's behaviour with exactly that syntax and it'll work; just not C_BRA_NEWLINE. It feels as if they're trying really hard to shove C_BRA_NEWLINE down your throat, much as Microsoft did with the aforesaid Paperclip. After hours of experimentation, during which time I seriously considered auditing all the S-Lang code and completely deleting every line involved in supporting C_BRA_NEWLINE at all, effectively lobotomizing the part of its brain that handles that feature at all, I finally figured out the problem.

It's the "c_set_style("jed");" line. That function call does not (as one might expect) set up the lower-level indentation-controlling variables to a canned set of values you can override. Instead it sets a variable somewhere that says "We will be using the canned set of values called 'jed.'" and then much later in the initialization process, long after all the code in the .jedrc file has finished executing, that command will be actually put into practice. If you have attempted to override some of the canned values from the template by setting the lower-level variables individually in .jedrc, too bad; at the later time when c_set_style really takes effect, your customized values get overwritten.

The workaround is to not call c_set_style at all. Instead, you must set all the lower-level variables individually, doing what c_set_style would have done but earlier, at the time when you can control it. The relevant section of my .jedrc now looks like this:

C_BRACE = 2;
C_Colon_Offset = 1;

In the JED FAQ there's a fair bit of discussion that acknowledges many people hate "C mode," and explains how to turn it off after trying to suggest to people that they really ought to give it a fair try first, because C mode is actually a good thing, honest! I suspect that what people really hate isn't C mode, it's C_BRA_NEWLINE. Just for me personally, C mode without C_BRA_NEWLINE is a joy to use. But C_BRA_NEWLINE is absolutely unacceptable to me. Your mileage may vary.

Wordstar and other key bindings

I, like many computer users of my vintage, like Wordstar editor command sequences. I think part of the appeal is that they use keys in the normal alphabetic range, so that it's easy for touch typists to enter commands without moving their hands from the "home" typing position. Wordstar commands are actually one reason I started using JOE in the first place. JED is from the EMACS tradition and uses EMACS keystrokes by default. It has modes called "wordstar" and "ide," both based on some approximation of the old Borland editors, and it strongly suggests in the documentation that "wordstar" mode is obsolete and you should use "ide" mode instead; "ide" is the JED author's own preferred mode. Up to now I've been using the default EMACS-like key bindings, and hating them, and that's been a big part of the reason I've only used JED for editing C code where the C mode (provided C_BRA_NEWLINE was turned off) was a valuable enough feature to be worth the lack of Wordstar commands.

In my recent investigations I decided to try JED's implementation of Wordstar commands. I tried the "ide" mode because that was what the documentation said to use, and I hated it and ended up switching to the supposedly-obsolete "wordstar" mode. The dealbreaker issue here was block command semantics: in "ide" mode, you press "^KB" to mark the beginning of a block, but you can't press "^KK" to mark the end. If you do, you get a message telling you not to do that. (Hint: the existence of such messages nearly always indicates a serious lapse in UI design.) Instead, the block is always from the starting location to the current location of the cursor, and then you have to cut or copy it. The fundamental concept of a persistently-marked chunk of text, just doesn't exist in "ide" mode even though that is fundamental to what makes the IDE editor supposedly being emulated, different from other editors. Dealbreaker.

This is especially weird because "wordstar" mode does support persistently-marked blocks, so it's clearly not an absolutely fundamental impossibility. There are some weirdnesses in "wordstar" mode's implementation: in particular, the block doesn't stay highlighted after you press "^KK", and it's apparent that it is really being copied into a buffer on block-close, because if you edit inside the block and then try to copy it, you get a copy of the contents when you marked it instead of the edited version. Nonetheless, there's clearly some kind of persistent marking going on because "^KY" seems to work - so why not make the whole thing really work as it should? The bottom line, though, is that in "wordstar" mode it implements blocks in a close enough approximation to what I'm used to, that I think I can live with it. In "ide" mode, the block semantics are broken enough to be unacceptable.

I have been gradually overriding the default wordstar-mode key bindings, with the general rule being that if I press a key combination and it doesn't do what I intended, then it'll be changed to do what I intended. I think the result will probably end up being very much like JOE's defaults, which are the main source for my current muscle-memory. Not only your but also mymileage may vary as I continue tweaking the configuration, but here are my current custom bindings:












Note that these should go inside the "if (BATCH == 0)" section at the top of .jedrc. I'm not sure what the consequences are of doing key bindings when in batch mode, but it seems to be discouraged.

"Delete window" is not exactly what JOE does on ^C, but this seems to match my usual usage pattern: I'll often open an extra file in a split window and then want to close it with ^C. It's not too big an imposition for JED to require that I type "^KX" instead of "^C" to exit the editor entirely.

^Z by default is some kind of window-scrolling thing (see also below); I prefer to make it suspend. I think the suspend command is called "spawn" because of history from other OSes where it actually spawns a subshell; on my Linux system, it's a proper suspend.

The duplicated sequences for ws_bol and ws_eol correspond to the "Home" and "End" keys on my desktop and laptop. For some reason these two keyboards don't send the same sequences for those keys (maybe because on the laptop they are actually two-key sequences, "Fn-Left" and "Fn-Right") and for some other reason, JED doesn't bind them properly by default anyway. It's nice to have them work for the first time in a long time.

Terminal support

Another dealbreaker: if I move the cursor to the bottom line of the window and then move it one more line down, JED in a default installation will jump ahead half a screen in the file to bring the new cursor location to the middle of the screen. This is, again, a jarring interruption. (Notice the theme here? Jarring interruptions are unacceptable.) I think I was actually tolerating that on C code all these years (I'm not going to go back to backups to check) but it's a dealbreaker for writing fiction, when I very often want to scroll through the text reading it slowly and not have to lose my place and pick it up again every half-page. I don't know if I do that less often when writing C, or if it's easier to pick up the lost place in C because of the different visual layouts of C and English, but whatever the reason, it annoyed me at least a little less with C.

A similar issue: when it scrolled horizontally because of a long line, it would also do that in annoyingly large jumps. Less of an issue, because you shouldn't write long lines anyway.

In what turned out to be a related point: JED would pretty often fail to use colour for syntax highlighting. It seemed to work in my local sessions, but not when I connected back to my home computer via SSH from elsewhere. This seemed to be related to its idea of terminal capabilities: I was working around it by manually setting my TERM environment variable to "ansi" on the remote sessions.

All of these turned out to be related to pessimistic assumptions about the terminal's capabilities. There is a comment in some S-Lang file somewhere about how Linux cannot scroll properly and so the TERM_CANNOT_SCROLL variable is set to 1, which has the effect of doing a "recenter" operation on every cursor movement outside the page... that is, the half-page jump I was complaining about. I had thought the JED author(s) actually wanted that behaviour, but it turns out that's their attempt at compromise when the terminal can't easily do proper scrolling. I don't know if the claim of Linux being broken was ever true, or might still be true of the text-mode console, but I set "TERM_CANNOT_SCROLL = 0;" at the bottom of .jedrc and now it's a lot pleasanter to use in my graphics-mode terminal windows.

I also set "USE_ANSI_COLORS = 1;", which seems to override the pessimistic guessing that colours are not supported on remote sessions, and "HORIZONTAL_PAN = -1;" so it will do horizontal scrolling smoothly on the entire window, instead of just one line in huge jumps. I suspect the default behaviour dates from an assumption that people would be using real terminals on slow serial lines, where redrawing the entire screen would be prohibitively expensive; it's no longer relevant for my use cases, not even when I'm connecting from remote over the Net, just because bandwidth is so much better nowadays. In the same spirit, I set "LINENUMBERS = 2;" to get column numbers as well (a feature I hadn't even known JED supported); that significantly increases network traffic but network traffic for a text editor is still cheap, and it's sometimes useful to have the column number.


Heheh! forgotten customizations... Dreaded upgrading nemesis. I'm glad WordStar fingerings still make music. I keep a DOS partition so I can write my large texts with PCWrite, state-of-the-art shareware of the 1980s which allows WordStar commands (and makes it very easy to do complex macros as well as producing lean files without wasteful formatting overhead).
Axel - 2010-09-05 10:06
I guess someone's age shows when he talks about lean files.
Axel - 2010-09-05 10:18
Still can't get JED to insert a tab in SH mode... I use a customized "cua" mode... I redefined ^I to self-insert, but I guess a similar thing is happening, that this gets overridden later on. The thing is, in my .jedrc I only have variable assignments, setkeys, and ()=evalfile("cua"); in the beginning...
PePa - 2015-11-09 01:44

(optional field)
(optional field)
Answer "bonobo" here to fight spam. ここに「bonobo」を答えてください。SPAMを退治しましょう!
I reserve the right to delete or edit comments in any way and for any reason.