Ticket #87 (closed enhancement: fixed)

Opened 7 years ago

Last modified 5 years ago

Need IDE init file

Reported by: gz Owned by: gb
Priority: normal Milestone: Cocoa IDE v1
Component: IDE Version:
Keywords: Cc:

Description

I'd like to make some personal customizations to the editor, but the editor stuff is not accessible when my openmcl-init.lisp is loaded. We need an init file that gets loaded when the IDE starts up.

Change History

comment:1 Changed 7 years ago by gb

  • Status changed from new to assigned

On a related note: the saved IDE doesn't load ~/openmcl-init.

In the TTY environment, openmcl-init is loaded in the initial listener thread. It -could- be loaded in the first IDE listener.

It's not rocket science to do so, but we should think a little about whether the editor customization file is loaded before or after the general init file.

comment:2 Changed 6 years ago by joswig

Clozure CL should have also an example customization file. Examples for:

  • new menu item in the menubar
  • new context menu
  • new hemlock command
  • new hemlock variable
  • setting a hemlock variable
  • loading a subsystem (list of available subsystems)
  • list of available hooks

comment:3 Changed 5 years ago by jaj

  • Priority changed from major to normal
  • Milestone set to Cocoa IDE v1

Change priority to normal, add to Cocoa IDE v1.

comment:4 Changed 5 years ago by gz

Actually, as Ron Garret pointed out on openmcl-devel, we just need some official way to ask whether you're running the IDE or the command-line version of CCL.

Then, once ticket #208 is fixed, the user will be able to do (when (ide-p) (load "my-ide-stuff")) in their ccl-init.lisp, and they can do it before or after or intertwined with other initializations. This will take care of users who run the IDE app. For IDE developers, who do (require'cocoa) to start up the IDE, we can just add an *ide-finished-loading-hook* which they can set to do whatever's desired in their ccl-init.lisp.

So I take my original request back. We don't need a second init file. We just need (ccl:ide-p) [or better yet (ccl:ide-p *application*)] and ccl::*ide-finished-loading-hook*, and this ticket can be closed.

comment:5 Changed 5 years ago by gb

I don't believe that doing IDE customization from ccl-init.lisp is necessarily adequate; ccl-init.lisp loads when the first listener starts up, and I think that one could plausibly want to customize things before that happens (like ... oh, the position and size of the first listener window, or the contents of the menubar before it becomes visible, or ...)

I believe that we've had this conversation before.

comment:6 Changed 5 years ago by gz

Why can't we load ccl-init before the first listener starts up, but start up a listener if an error happens?

comment:7 Changed 5 years ago by gb

Sure. Anyone who's ccl-init prompts for input or writes progress or other messages would have to change, and the fact that it'd run in the initial thread rather than in the initial listener thread might necessitate other changes in some (admittedly obscure) cases, but many people wouldn't have to change anything and those that do would be glad to do so because they'd reap the benefits of being able to load a single file.

Those benefits escape me at the moment; I'm being sarcastic here because I don't understand why this has become a better idea now than it was all of the other times that I remember it being discussed and dismissed.

comment:8 Changed 5 years ago by gz

I don't remember this being discussed and dismissed, perhaps it happpened while I was away, or perhaps I blocked it out. In any case, humor me and lead me through it again. I can't even tell which parts of your first paragraph are sarcastic and which aren't, so I still don't know the answer to my question.

As far as I understand, the current design is as follows:

(1) There is one init file that will be loaded before the first listener is started up. This init file will have the advantage of being able to affect the look and feel of the first listener, but will have some disadvantages. If I'm parsing the last comment correctly, there will be restrictions on prompting for input or writing progress messages, and it might have some subtle disadvantages due to running in the initial thread rather than the more common evaluation context (possibly having to do with handling of errors?).

(2) There is another init file that will be loaded just after the first listener is started up. This init file will not be able to affect the look and feel of the first listener, but will be able to prompt for input and write progress reports with impunity, and will have standard error handling and possibly other subtle benefits of not running in the initial thread.

Is that basically the plan?

My question is, is it not possible to have the advantages of both (1) and (2) and the disadvantages of neither? The approach I would take is to try to load an init file before the first listener, but respond to attempts at prompting and progress reports and break loops by popping up a listener. If there is an issue with error handling when loading the init in the initial thread, then perhaps we could spawn off a thread to load the init, but still without creating a listener window until necessary.

comment:9 Changed 5 years ago by gb

What I remember as our having discussed and rejected the idea that you propose (or something like it) may have been me thinking out loud about it and hearing either silence or something else that I interpreted as agreement; I'm fairly sure that this would have happened around the time that this ticket was first opened.

The plan (partly implemented in the current trunk code) is as you understand it. In detail:

  • at a point when the Cocoa application object (the global NSApplication instance) has initialized itself but before it's started its event loop, an IDE-specific init file ("~/ccl-ide-init", IIRC) is loaded. That happens in an environment where it's hard to do interactive I/O, and it happens in the initial (event) thread. Since it also happens before much of anything happens in the IDE, it can affect things that happen subsequently in the IDE: it can modify the menubar before it's drawn, etc.
  • when the first listener starts up, it loads the standard (non-IDE-specific) ccl-init file. The dynamic environment in which this occurs (the set of thread-specific special bindings, in particular) is pretty similar to the environment in which this file loads in the non-IDE case; assignments to special variables that have thread-specific bindings don't affect static bindings or bindings in other threads.

(The listener thread also has full access to a *TERMINAL-IO* stream.)

It's possible that many people's init files don't do anything that's at all sensitive to the dynamic environment in which they're loaded; it seems equally possible that some people's init files do do such things.

Note that the specific case of popping up a listener to handler a break loop (or to call READ) in the initial thread involves the same kinds of issues that make it hard to pop up a listener to enter a break loop in the initial (event) thread when an error occurs: that thread can either be running an event loop or a break loop, but it may be very hard to do both at the same time.

On the one hand, I think that it's absolutely necessary to load IDE customization early (before the event loop starts); on the other, it's hard to know how to best handle errors and I/O issues for user code that runs in that environment. That hasn't gotten any clearer since the ticket was ticket was opened, but with an initial implementation in place it may become clearer. Aside from the objections noted above, subjecting the loading of the standard init file to the same issues seems pointless.

comment:10 Changed 5 years ago by rongarret

FWIW, IMHO this issue is resolved by the ccl-ide-init.lisp file. But the behavior of this file is not documented. Maybe that's all that's needed to resolve this.

comment:11 Changed 5 years ago by gz

  • Status changed from assigned to closed
  • Resolution set to fixed

Just for the record, I still believe that we could figure out a way to do things that doesn't make it necessary to have two init files just so that each can have a slightly different set of disadvantages. But at this point, it is what it is. As I now have not just one but two places I can put editor customizations, my issue is certainly resolved and I'm closing the ticket.

comment:12 Changed 5 years ago by gb

I was going to say that there's no reason that someone who wanted to lump IDE customization in with non-IDE customization couldn't do so, and that a regular "ccl-init" file that contained:

(setq ccl::*save-definitions* t)

#+ccl-ide  ; I guess that no one ever compiles their init file, so #+ would dtrt
(progn
  (hi::bind-key "Self Insert" #k"space")
)

would work fine, but of course it wouldn't: the reader would need to know enough about #k to know what to skip over when *READ-SUPPRESS* is true, and it's reasonable to assume that many #+ccl-ide things would involve use of #k, #/, and any other current or future IDE-specific extensions.

So, unless we kludged something up (provided dummy versions of any bridge/Hemlock reader macros, or something) the IDE-specific customizations would pretty much have to be kept in a separate file (or read from strings, or something equally ugly). We can either view this effective requirement as being an unfortunate consequence of some unspecified bad design somewhere (presumably surmountable by "just putting more thought into it") or a natural consequence of the fact that IDE customization code is qualitatively different from (is intended to be compiled and run in a different environment than) "standard CL" customization code. Since I tend to believe the latter explanation, I don't find the two-init-files scheme onerous or unnatural and tend to see problems with the single-init-file scheme as being unsurprising consequences of it being ... um ... the wrong idea; so far at least, putting thought into it has tended to confirm that point of view.

All that said, there's no reason that I can think of why one can't load IDE customizations from (a file loaded from) one's init file, and having these take effect when one's regular init file loads (when the first listener appears) is often adequate (this is likely to be true of editor customizations/key bindings.) There may be other kinds of IDE customizations that need to run earlier (e.g., changing the menubar before it's drawn for the first time). Forcing the standard init file to load at this time (so that it can then load/read-from-string/whatever that early IDE-customization code) doesn't strike me as being too well thought out, and AFAICT the motivation for that - It'd Be Really Neat And Would Kind Of Almost Work If There Was A Single Init File - doesn't seem too well-considered, either.

Note: See TracTickets for help on using tickets.