DrRacket Workspaces?

I would like to start a conversation about adding workspaces to DrRacket.

Workspaces are (in my experience) a common feature in modern IDEs:

  • VSCode calls them "workspaces" and
  • the JetBrains family of IDEs (e.g. IntelliJ, Goland, Android Studio) call them "projects".

I'm going to define a workspace as providing the following (probably incomplete) set of features:

  • Defining a directory containing project files.
  • Starting from the workspace directory when saving newly created files.
  • Providing one or more views showing the file and/or project structure.
  • Remembering open files and reopening them when the IDE is restarted.
  • Tracking other workspace preferences as appropriate.

Currently there are some plugins for DrRacket that provide some of these features:

  • files-viewer provides:
    • naming of directory as a "workspace"
    • File Manager view showing directory structure
  • drracket-workspaces provides:
    • ability to a set of open files by "workspace" name
    • but:
      • there is no update to an existing workspace and
      • an existing workspace can't be deleted by name, all must be cleared at the same time
  • drracket-restore-workspace provides:
    • reopening of files from the last shutdown of DrRacket

I have some concerns about implementing workspaces as part of a plugin as opposed to a first-class addition to DrRacket:

  • Saving a new file seems to be part of core DrRacket functionality and may not be simple (or possible) for a plugin to hook into.
  • There may need to be some support in the DrRacket core for per-workspace preferences.
  • It just seems useful to integrate something like workspaces into the DrRacket core (or at least discuss it as an option).

These concerns may well stem from an inadequate understanding of the plugin API on my part. Or it may be that some minor changes to the plugin API would make it possible for plugins to support workspaces.

That's all I have to say for now. I thought this post might start a discussion, and if not no big deal.


  1. This is probably the most annoying DrRacket behavior I personally encounter on a regular basis. I'm running Ubuntu Linux. If I start DrRacket from my project directory it works fine (the file chooser starts in that directory) but I typically launch DrRacket from an icon on my launcher bar. Every time I go to save a file for the first time I must navigate down from my home directory. Not the end of the world, but a bit irritating (over and over again). ↩︎

1 Like

Read the paragraph "Racket turns extra-linguistic mechanisms into linguistic constructs." to see why "projects" aren't popular in Racket.

I seem to recall discussions on the mailing list on the topic, but I couldn't locate them.
Maybe someone else with better memory can direct you to the old discussions.

Some features like a "file manager" to quickly find files in the directory structure
doesn't conflict with the manifesto. Screen sizes have grown and reserving
screen estate for such a thing is no longer a problem.

Note that normal Racket programs normally don't have the excessive number of files
that some programming languages do (like Swift where the convention is that each class and each extention get a separate file). Openening the handful of files you are actively working on
and using tabs to switch between them (use cmd-1, cmd-2 etc to switch between them)
seem to work fine in most cases.

  • Remembering open files and reopening them when the IDE is restarted.
    That's easily solved - don't close DrRacket :wink:

There's also a simple workspaces quickscript listed on this page:

It merely has menu items to save/restore set of opened files. Since a workspace is saved into a file, several workspaces can be defined.


At the link above there's also an Open recent quickscript, which I use all the time (while I don't use workspaces usually). It improves on DrRacket's open recent menu item:

  • It has a search box
  • It can open multiple files at once by unchecking the check box at the bottom
  • It can be used to switch between tabs.

The script doesn't have a key shortcut by default, but I change it to ctl-alt-o by adding:

  #:shortcut #\o
  #:shortcut-prefix (ctl alt)

below #:label.


At the link above there is also a new file in same directory quickscript, which should appease your frustration of going back to the home directory when saving a new file.

3 Likes

Also, if you turn your project into a package/collection you have the following benefits:

  • You can use the File|Open require path... (which has a search box) and type the project name to quickly find a file even in a subdirectory
  • You can run raco setup my-project and raco test my-project from anywhere, which compiles/checks the whole project at once (and compile-omit-paths, test-omit-paths can be specified in an info.rkt)
  • You can use require my-project/subdir/file (usually within a module that's not part of the project itself)

To make it a collection: In the parent directory of my-project, type:

raco pkg install --link my-project

Although your life will be even more joyful if you start your project with raco pkg new my-project to create a new directory pre-filled with yummy goodies (scribble docs, license, readme, info.rkt, …). If you want to publish your package on the website, you should definitely do that.
For an existing project it may involves something like

mv my-project my-project2 && \
raco pkg new my-project && \
mv my-project2/*.rkt my-project

More info on packages: Package Management in Racket

1 Like

Fun shell fact, the line continuation backslashes are not needed if the line ends in && (or |, or ||).

5 Likes

It’s worth quoting

  1. Racket turns extra-linguistic mechanisms into linguistic constructs.When programmers must resort to extra-linguistic mechanisms to solve a problem, the chosen language has failed them. Even if it is not always obvious how to fix such failures, programming language researchers ought to accept the general idea and try to work on finding the proper linguistic mechanisms. Due to Racket’s uses, the language currently internalizes several resource-management mechanisms that are often found in the underlying operating system. Similarly, this philosophy prohibits the idea of “projects,” as found in other IDEs, because this also externalizes resource management, linking, and other aspects of program creation.

But so is the aside

This guideline does not mean that linguistic constructs ought to replace all tools. It merely means that the creation of every tool must raise the question whether it should be a tool or a part of the language. Some tasks are best left to tools, others are better realized as extensions of the language. Finding a good balance is a difficult problem. For example, the creator of a Racket library or a large system may very well wish to think in terms of projects, but a novice student must never have to say “create project” before writing and running a “hello world” program

On my wish list is a DrRacket Professional Edition with all the plugins and quickscripts (and templates browser like .net) - but I’m not sure about projects because I like not having to make a project.

3 Likes

I wouldn't want to make workspaces/projects/whatever necessary in order to use DrRacket (or Racket for that matter). It's just that there are potentially advantages to having something of the sort.

I typically jump from one thing to another (likely due to a combination of retirement and ADHD). When I go back to a previous project or workspace it's convenient for me to have the IDE remember what I was doing the last time, what files were open, what commands and tests I had configured. It saves me time and mental churn.

Yes, some of the languages I use have project-level semantics built in. Sometimes that's convenient and sometimes it's a pain, but it comes with the language, not the IDE.

That's not at all what I'm suggesting. I'm just looking at DrRacket as a great tool that is missing some helpful conveniences that sort of group together in my mind as a "workspace".

3 Likes

Somewhat related: I used WinEdt a lot to edit LaTeX files. A very handy feature was to declare one of the files in the editor the main file. The idea was to be able to edit multiple files simultaneously, and when you hit the "compile" button, all the files are saved and the LaTeX compiler is run on the main file, that (probably) includes all the other files you are working on.

I was recently working with three LaTeX files simultaneously in other editor, and I had some problems with the layout of a table that was defined not in the main file. So I had to make the fixes, remember to switch to the main file, and hit the compile button there. It was painful because half of the times I forgot to switch the file and got a nasty error.

I had a similar problem with Python a few weeks ago. I had the main file, and a file with helper functions, and debugging/fixing the helper functions was painful because I had to switch to the main file to run it.

Also, a trick that I used in WinEdt was to use a .bat file as the main file, so I could run arbitrary code, like compiling a file in fortran and then running it with an input in a .txt file, or perhaps compiling and chaining a few files. The advantage was that I can edit all the files simultaneously and when I hit the compile button, then all are saved and compiled/executed/whatever and it was very easy to write the details in the .bat file.

The disadvantage was that WinEdt has too many options to configure what happens when you hit the run button. The defaults for the usual files are good, but adding handlers for new extensions is not newbie friendly.

So my feature request, is to be able to mark a file as the main file, and make the "run" button run that file instead of the file in the selected tab.

2 Likes

I like it but feel a beginner could get in a state where they re hitting run but it is not running the tab they expect and getting confused.

  • Maybe put a run button on each tab? or on tabs that don't have (provide ...)'s ?

A related difference between DrRacket and other IDE's is the meaning of the 'Run' button:

  • Other IDE's often have a distinct Run and Debug buttons.
  • In DrRacket Run is the same as Debug on other IDE's. (and contributes to complaints about Racket being slow)

If someone wants 'Run' like other IDE's their only option is to open a comment line and type

Racket myfile.rkt

You can of course turn off debugging and profiling, but that is hidden behind a menu, and we never suggest it because there is still a performance cost to running from DrRacket.

The JetBrains IDEs (IntelliJ, Goland, Android Studio, etc.) provide a way to configure a variety of "run" and "test" configurations. They appear in a dropdown. The "run" and "debug" icons just activate the current choice.

1 Like

It seems that this behaviour can be overridden actually:
https://docs.racket-lang.org/tools/drracket_unit.html#(meth._(((lib._drracket%2Ftool-lib..rkt)._drracket~3aunit~3aframe~25)._execute-callback))

So a DrRacket plugin should be able obtain this behaviour. (or hopefully the upcoming Quickscripts hooks).

1 Like

One thought I've had along these lines would be to make a set of open files (maybe all the tabs in one frame?) share their program state in the sense that each separate interactions window was working with the same program, but with the bindings from the corresponding definitions window available to it. So hitting "Run" on any one of them would effectively run all of them and let you explore what was going on everywhere. (There are some issues with IO and perhaps other things to think through.)

1 Like

I prefer that only the main tab runs (with whatever definition of run it has). It fit's better my mental model. The main program may require the other files (perhaps in different phases!), r the other files may be data files like a txt.

I remember in VB6, that you can open "groups" that has multiple "projects", each project has multiple files. The main project was the program, and the other projects were dll. So the run button first "run" the dll, register them in the magic COM world[1], and then the main program used them. IIRC the interaction windows was connected only to the main program.

Yep. IIRC in WinEdt it was not super clear if you had defined the main file (and the run button was running that file), or the main file was undefined (and the run button just compile the tab that was visible). It was some subtle difference on the icons (grey vs dark green?) that was sometimes very confusing.

[1] And complained if you were not an administrator.

1 Like

A module may have a main or test module that should be run, so having the "Run" button disappear for those modules would be very inconvenient (and in my opinion quite confusing if you don't know the reason for the disappearance).

1 Like

Robby's point in saying "with the bindings from the corresponding definitions window available to it" is that if a file does not provide certain functions, you cannot access them if all you have is an interaction with the "main" tab.

Here's a proof-of-concept quickscript that open/switches to "main.rkt" in the same directory and runs the interactions.

To try it (after installing it and "Scripts|Manage scripts...|Reload menu"), click on Scripts|Run main file test and follow the instructions.

This assumes that "maink.rkt" is always the main file in the directory, but I suspect you don't want to be bound to this name.
This would require either:

  • to save the main filename to disk
  • or to mark the main file every time DrRacket is started (and make the script #:persistent)

Optionally:

  • a "Go back" button/menu item could go back to the original tab before the tab switch
  • instead of a menu item, it could be a button next to the "Run" button. A DrRacket plugin would also be able to override Run, but I'm not sure that's desirable here, as one may want to also retain the Run per file behaviour.

I'm not sure how much of this is aligned with what you want – let me know.

1 Like

This does make sense to me too; my thinking was (a few steps beyond and not clearly explained!) more along the lines of what to do with the interactions windows of the window where you are editing and hit the "Run" button. My thinking was that running the "main" program would eventually require the file that you're editing (otherwise, why are you running that one and editing this one?), so then you'dbe interested in what's going on in that module and so getting an alternative view on your program by doing stuff in the interactions window of the file you happen to be editing in would be helpful.

You do raise a good point about requires that cause other, non-main files to be instantiated multiple times in multiple phases (other strange things will happen with dynamic-require and current-namespace and friends) but I feel pretty good that we could figure something out that would work well and not be confusing.

Anyway, I've had this thought for a very long time but not found the time to act on it, so we don't need to worry about me breaking anything anytime soon! :rofl: