From de37f7827a599473f94438c77588955f359a9c26 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Fri, 27 Feb 2026 15:02:35 +0100 Subject: [PATCH 01/21] started writing recipes for the three kinds of UI we have --- .../LanguageServerProtocol.md | 28 ++++ .../SalixRecipes/SalixRecipes.md | 5 + .../Recipes/UserInterfaces/UserInterfaces.md | 46 ++++++ .../VanillaHTML5/VanillaHTML5.md | 149 ++++++++++++++++++ 4 files changed, 228 insertions(+) create mode 100644 courses/Recipes/UserInterfaces/LanguageServerProtocol/LanguageServerProtocol.md create mode 100644 courses/Recipes/UserInterfaces/SalixRecipes/SalixRecipes.md create mode 100644 courses/Recipes/UserInterfaces/UserInterfaces.md create mode 100644 courses/Recipes/UserInterfaces/VanillaHTML5/VanillaHTML5.md diff --git a/courses/Recipes/UserInterfaces/LanguageServerProtocol/LanguageServerProtocol.md b/courses/Recipes/UserInterfaces/LanguageServerProtocol/LanguageServerProtocol.md new file mode 100644 index 000000000..15da08bd3 --- /dev/null +++ b/courses/Recipes/UserInterfaces/LanguageServerProtocol/LanguageServerProtocol.md @@ -0,0 +1,28 @@ +--- +title: "VScode and the Language Server Protocol" +keywords: + - LSP + - VScode + - "Visual Studio Code" + - "Language Server Protocol" +--- + +#### Synopsis + +Recipe for creating an IDE for your language based on the Language Server Protocol + +#### Syntax + +#### Types + +#### Function + +#### Description + +(((TODO))) + +#### Examples + +#### Benefits + +#### Pitfalls \ No newline at end of file diff --git a/courses/Recipes/UserInterfaces/SalixRecipes/SalixRecipes.md b/courses/Recipes/UserInterfaces/SalixRecipes/SalixRecipes.md new file mode 100644 index 000000000..2df905aa5 --- /dev/null +++ b/courses/Recipes/UserInterfaces/SalixRecipes/SalixRecipes.md @@ -0,0 +1,5 @@ +--- +title: Constructing web-based user-interfaces with Salix +--- + +(((TODO))) \ No newline at end of file diff --git a/courses/Recipes/UserInterfaces/UserInterfaces.md b/courses/Recipes/UserInterfaces/UserInterfaces.md new file mode 100644 index 000000000..74e6c0063 --- /dev/null +++ b/courses/Recipes/UserInterfaces/UserInterfaces.md @@ -0,0 +1,46 @@ +--- +title: User Interfaces +keywords: + - userinterfaces + - visualization + - UX + - UI + - HTML + - HTML5 + - Servlets + - WebServer +--- + +#### Synopsis + +Recipes for writing Rascal programs that create interactive _visual_ user interfaces + +#### Syntax + +#### Types + +#### Function + +#### Description + +These recipes are useful if have one of the following intentions for your programming language or DSL: +* creating a software visualization tool (interactive or not) +* creating an interactive or even live programming environment +* creating an full-featured editor +* creating a coupled visualization (code <-> visual) +* creating visual statistical overviews and reports of your empirical data (extracted from code) +* creating visual modeling tools +* etc. + +These recipes fall into three major technological categories: +* ((VanillaHTML5)) recipes explain how to generate and serve HTML5 content directly from Rascal into your IDE web view or into your Desktop browser. +* ((SalixRecipes)) explain how to use the [Salix]((org.rascalmpl.salix-core)) framework to build user interfaces for the browser (or the IDE web view) in Rascal. +* ((LanguageServerProtocol)) recipes explain how to construct a full featured IDE with Visual Studio Code and the Language Server Protocol. + + +#### Examples + +#### Benefits + +#### Pitfalls + diff --git a/courses/Recipes/UserInterfaces/VanillaHTML5/VanillaHTML5.md b/courses/Recipes/UserInterfaces/VanillaHTML5/VanillaHTML5.md new file mode 100644 index 000000000..5acd0667a --- /dev/null +++ b/courses/Recipes/UserInterfaces/VanillaHTML5/VanillaHTML5.md @@ -0,0 +1,149 @@ +--- +title: Vanilla HTML5 user interfaces +keywords: + - HTML5 + - JavaScript + - WebServer + - Content +--- + +#### Synopsis + +Creating interactive visual content for the browser using Rascal's HTML and HTTP low-level API support. + +#### Syntax + +#### Types + +#### Function + +#### Description + +To start with a simple "webserver" in Rascal, all you really need is to import ((module:Content)) and +write a server function: + +```rascal-shell +import Content; +// A server in Rascal terms is a function that takes an HTTP ((Content-Request)) and produces an HTTP ((Content-Response)): +Response myWebServer(Request q) = plain("Hello \World\"); +// Let's test the server locally to see what the `plain` utility function produces as ((Content-Response)): +myWebServer(get("index.html")) +// and the REPL will spin-up an actual server by itself like this: +content("myServer", myWebServer) +``` + +There are handy shorthands in ((module:Content)) like ((plainText)) and ((Library:Content-html)) and ((Library:Content-file)) to directly +stream strings, html and files to the web client. + +The HTTP ((module:Content)) servers that start from the REPL automatically are also managed automatically. If you use the same tag, the server is reloaded. +Also inactive servers are removed and their data is garbage collected after 30 minutes of inactivity. + +#### Examples + +**Generating HTML as text** is done using the ((StringTemplate)) recipe. For example: +```rascal-prepare +import Content; +``` + +```rascal-commands,continue +words = ["aap", "noot", "mies"]; +str generateList(list[str] words) + = "\ + '\\ + '<}>\"; +``` + +```rascal-shell,continue +// this is the generated content as plain/text mimetype +plainText(generateList(words)) +// this is the generated content as plain/html mimetype +html(generateList(words)) +``` + +**Generating abstract HTML is done using ((lang::html::AST)) algebraic data-type for HTML. For example: +```rascal-shell,continue +import lang::html::AST; +import lang::html::IO; +``` + +```rascal-commands,continue +HTMLElement generateUL(list[str] words) = ul([li([text(w)]) | w <- words]); +// and we can see the generated HTML +plainText(writeHTMLString(generateUL(words))) +// or view the HTML as rendered by the browser +html(writeHTMLString(generateUL(words))); +``` + +**Interactive content** is not much more complicated to setup, but it does require JavaScript programming. +We stay with the Request/Response system. Next to the request for the main page we +we also receive asynchronous http requests (via the "fetch" function in JavaScript). In this next server definition we use ((Declarations-Function)) overloading to handle +each request URL with a different function body: + +```rascal-commands,continue +// In this demo we use a simple integer to demonstrate server-side data and state: +int counter = 0; +// The first overload serves the main page, which includes a call to `fetch` the new counter state (in JavaScript): +Response myInteractiveServer(get("/")) + = response("\ + ' \ + ' \Counter: \\\ + ' \