From 871517cdb359110d4e9c4c8c27c6321a9fadea4b Mon Sep 17 00:00:00 2001 From: Gerhard Dorn <67096719+dorn-gerhard@users.noreply.github.com> Date: Tue, 19 Sep 2023 18:33:43 +0200 Subject: [PATCH 01/10] Linebreaks with small spacing in Firefox (#2605) Co-authored-by: Fons van der Plas --- frontend/editor.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontend/editor.css b/frontend/editor.css index 3e3ab1d2ef..97f5913be3 100644 --- a/frontend/editor.css +++ b/frontend/editor.css @@ -192,6 +192,11 @@ pluto-output p { line-height: 1.45em; } +/* This allows a linebreak in Markdown using backslash with smaller spacing compared to paragraph in firefox */ +pluto-output br { + margin-block-end: 0; +} + pluto-output p:first-child { margin-block-start: 0px; } From 50b2dc50780da5369d038f4a29e9639cba88b10b Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Wed, 20 Sep 2023 15:05:54 +0200 Subject: [PATCH 02/10] workspace_custom_startup_expr as String (#2654) Co-authored-by: Paul Berg --- src/Configuration.jl | 6 +++--- src/evaluation/WorkspaceManager.jl | 4 +++- test/Configuration.jl | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Configuration.jl b/src/Configuration.jl index 2b7eed6ae9..b99c429723 100644 --- a/src/Configuration.jl +++ b/src/Configuration.jl @@ -156,7 +156,7 @@ These options are not intended to be changed during normal use. - `workspace_use_distributed_stdlib::Bool? = $WORKSPACE_USE_DISTRIBUTED_STDLIB_DEFAULT` Should we use the Distributed stdlib to run processes? Distributed will be replaced by Malt.jl, you can use this option to already get the old behaviour. `nothing` means: determine automatically (which is currently the same as `true`). - `lazy_workspace_creation::Bool = $LAZY_WORKSPACE_CREATION_DEFAULT` - `capture_stdout::Bool = $CAPTURE_STDOUT_DEFAULT` -- `workspace_custom_startup_expr::Union{Nothing,Expr} = $WORKSPACE_CUSTOM_STARTUP_EXPR_DEFAULT` An expression to be evaluated in the workspace process before running notebook code. +- `workspace_custom_startup_expr::Union{Nothing,String} = $WORKSPACE_CUSTOM_STARTUP_EXPR_DEFAULT` An expression to be evaluated in the workspace process before running notebook code. """ @option mutable struct EvaluationOptions run_notebook_on_load::Bool = RUN_NOTEBOOK_ON_LOAD_DEFAULT @@ -164,7 +164,7 @@ These options are not intended to be changed during normal use. workspace_use_distributed_stdlib::Union{Bool,Nothing} = WORKSPACE_USE_DISTRIBUTED_STDLIB_DEFAULT lazy_workspace_creation::Bool = LAZY_WORKSPACE_CREATION_DEFAULT capture_stdout::Bool = CAPTURE_STDOUT_DEFAULT - workspace_custom_startup_expr::Union{Nothing,Expr} = WORKSPACE_CUSTOM_STARTUP_EXPR_DEFAULT + workspace_custom_startup_expr::Union{Nothing,String} = WORKSPACE_CUSTOM_STARTUP_EXPR_DEFAULT end const COMPILE_DEFAULT = nothing @@ -298,7 +298,7 @@ function from_flat_kwargs(; workspace_use_distributed_stdlib::Union{Bool,Nothing} = WORKSPACE_USE_DISTRIBUTED_STDLIB_DEFAULT, lazy_workspace_creation::Bool = LAZY_WORKSPACE_CREATION_DEFAULT, capture_stdout::Bool = CAPTURE_STDOUT_DEFAULT, - workspace_custom_startup_expr::Union{Nothing,Expr} = WORKSPACE_CUSTOM_STARTUP_EXPR_DEFAULT, + workspace_custom_startup_expr::Union{Nothing,String} = WORKSPACE_CUSTOM_STARTUP_EXPR_DEFAULT, compile::Union{Nothing,String} = COMPILE_DEFAULT, pkgimages::Union{Nothing,String} = PKGIMAGES_DEFAULT, diff --git a/src/evaluation/WorkspaceManager.jl b/src/evaluation/WorkspaceManager.jl index ba798bb114..e6f44eda44 100644 --- a/src/evaluation/WorkspaceManager.jl +++ b/src/evaluation/WorkspaceManager.jl @@ -73,7 +73,9 @@ function make_workspace((session, notebook)::SN; is_offline_renderer::Bool=false Status.report_business_planned!(init_status, Symbol(3)) Status.report_business_planned!(init_status, Symbol(4)) - Malt.remote_eval_wait(worker, session.options.evaluation.workspace_custom_startup_expr) + let s = session.options.evaluation.workspace_custom_startup_expr + s === nothing || Malt.remote_eval_wait(worker, Meta.parseall(s)) + end Malt.remote_eval_wait(worker, quote PlutoRunner.notebook_id[] = $(notebook.notebook_id) diff --git a/test/Configuration.jl b/test/Configuration.jl index 4d2d6c2f54..8b92d5b179 100644 --- a/test/Configuration.jl +++ b/test/Configuration.jl @@ -128,9 +128,10 @@ end @testset "disable mimetype via workspace_custom_startup_expr" begin 🍭 = ServerSession() 🍭.options.evaluation.workspace_use_distributed = true - 🍭.options.evaluation.workspace_custom_startup_expr = quote + 🍭.options.evaluation.workspace_custom_startup_expr = """ + 1 + 1 PlutoRunner.is_mime_enabled(m::MIME"application/vnd.pluto.tree+object") = false - end + """ nb = Pluto.Notebook([ Pluto.Cell("x = [1, 2]") From 3ee127597b007d627971ed5326643fe9f03074bd Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Thu, 21 Sep 2023 18:05:56 +0200 Subject: [PATCH 03/10] release 0.19.28 --- Project.toml | 2 +- frontend/featured_sources.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Project.toml b/Project.toml index 7292cf6847..740b6a12aa 100644 --- a/Project.toml +++ b/Project.toml @@ -2,7 +2,7 @@ name = "Pluto" uuid = "c3e4b0f8-55cb-11ea-2926-15256bba5781" license = "MIT" authors = ["Fons van der Plas "] -version = "0.19.27" +version = "0.19.28" [deps] Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" diff --git a/frontend/featured_sources.js b/frontend/featured_sources.js index 5acc0b97d9..e0dd1b0822 100644 --- a/frontend/featured_sources.js +++ b/frontend/featured_sources.js @@ -2,8 +2,8 @@ export default { // check out https://github.com/JuliaPluto/pluto-developer-instructions/blob/main/How%20to%20update%20the%20featured%20notebooks.md to learn more sources: [ { - url: "https://cdn.jsdelivr.net/gh/JuliaPluto/featured@v2/pluto_export.json", - integrity: "sha256-fDkEwI4YcuoCcQPZQmafTwnHD0evKyq0dGLEL+XLjZA=", + url: "https://cdn.jsdelivr.net/gh/JuliaPluto/featured@v3/pluto_export.json", + integrity: "sha256-y2E/niS8Em5a4wfSupsmDi0JaTrKSI0WF9DBkfEiQYQ=", }, ], } From 91c169573f6f2bbc8106e339ded251a31bceaeb8 Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Wed, 27 Sep 2023 19:41:21 +0200 Subject: [PATCH 04/10] Support interrupt on Windows soon! (#2659) --- Project.toml | 2 +- src/evaluation/WorkspaceManager.jl | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Project.toml b/Project.toml index 740b6a12aa..9587b46a28 100644 --- a/Project.toml +++ b/Project.toml @@ -39,7 +39,7 @@ HTTP = "^1.5.2" HypertextLiteral = "0.7, 0.8, 0.9" LoggingExtras = "0.4, 1" MIMEs = "0.1" -Malt = "1.0.3" +Malt = "1.1" MsgPack = "1.1" PrecompileSignatures = "3" PrecompileTools = "1" diff --git a/src/evaluation/WorkspaceManager.jl b/src/evaluation/WorkspaceManager.jl index e6f44eda44..178b44f5f9 100644 --- a/src/evaluation/WorkspaceManager.jl +++ b/src/evaluation/WorkspaceManager.jl @@ -641,10 +641,8 @@ function interrupt_workspace(session_notebook::Union{SN,Workspace}; verbose=true return true end - if Sys.iswindows() - verbose && @warn "Unfortunately, stopping cells is currently not supported on Windows :( - Maybe the Windows Subsystem for Linux is right for you: - https://docs.microsoft.com/en-us/windows/wsl" + if (workspace.worker isa Malt.DistributedStdlibWorker) && Sys.iswindows() + verbose && @warn "Stopping cells is not yet supported on Windows, but it will be soon!\n\nYou can already try out this new functionality with:\n\nPluto.run(workspace_use_distributed_stdlib=false)\n\nLet us know what you think!" return false end From fe491d96239e4ac12ef5a84bceb46d4b91de607f Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Wed, 27 Sep 2023 19:44:51 +0200 Subject: [PATCH 05/10] Update Project.toml --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 9587b46a28..5a3222a5ee 100644 --- a/Project.toml +++ b/Project.toml @@ -2,7 +2,7 @@ name = "Pluto" uuid = "c3e4b0f8-55cb-11ea-2926-15256bba5781" license = "MIT" authors = ["Fons van der Plas "] -version = "0.19.28" +version = "0.19.29" [deps] Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" From 82185cf3d56aef36eb598d2b38c7209ec4b46e61 Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Wed, 27 Sep 2023 22:34:35 +0200 Subject: [PATCH 06/10] Update Julia Computing to JuliaHub in sponsors list --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 613c7a3cf4..2d974b6881 100644 --- a/README.md +++ b/README.md @@ -188,7 +188,7 @@ Development of Pluto.jl is partially sponsored by |----|----| | MIT logo | The free online course _[Introduction to Computational Thinking](https://computationalthinking.mit.edu)_ at **MIT** uses Pluto notebooks to teach scientific computing in a new way. Homeworks react to the student in realtime, with _live answer checks and visualizations_ while you solve problems. | | QuEra logo | **QuEra Computing** uses a Pluto notebook as an online dashboard to control their _quantum computer_! | -| Julia Computing logo | [JuliaHub](https://juliahub.com) by **Julia Computing** enables the creation and editing of Pluto notebooks *on the cloud*! | +| Julia Computing logo | [**JuliaHub**](https://juliahub.com) enables the creation and editing of Pluto notebooks *on the cloud*! | | NumFOCUS logo | The mission of **NumFOCUS** is to promote open practices in research, data, and scientific computing by serving as a fiscal sponsor for open source projects and organizing community-driven educational programs. | _Created by [**Fons van der Plas**](https://github.com/fonsp) and [**Mikołaj Bochenski**](https://github.com/malyvsen). Inspired by [Observable](https://observablehq.com/)._ From 049ff094a2d2495f757fb9a1422281fea3e285fa Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Wed, 27 Sep 2023 22:46:04 +0200 Subject: [PATCH 07/10] readme: update juliahub sponsor --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2d974b6881..39ba98b02b 100644 --- a/README.md +++ b/README.md @@ -188,7 +188,7 @@ Development of Pluto.jl is partially sponsored by |----|----| | MIT logo | The free online course _[Introduction to Computational Thinking](https://computationalthinking.mit.edu)_ at **MIT** uses Pluto notebooks to teach scientific computing in a new way. Homeworks react to the student in realtime, with _live answer checks and visualizations_ while you solve problems. | | QuEra logo | **QuEra Computing** uses a Pluto notebook as an online dashboard to control their _quantum computer_! | -| Julia Computing logo | [**JuliaHub**](https://juliahub.com) enables the creation and editing of Pluto notebooks *on the cloud*! | +| JuliaHub logo | [**JuliaHub**](https://juliahub.com) enables the creation and editing of Pluto notebooks *on the cloud*! | | NumFOCUS logo | The mission of **NumFOCUS** is to promote open practices in research, data, and scientific computing by serving as a fiscal sponsor for open source projects and organizing community-driven educational programs. | _Created by [**Fons van der Plas**](https://github.com/fonsp) and [**Mikołaj Bochenski**](https://github.com/malyvsen). Inspired by [Observable](https://observablehq.com/)._ From 3f108c0a461123e8c19cdff27e6459b118a6ee1f Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Mon, 2 Oct 2023 16:04:18 +0200 Subject: [PATCH 08/10] Button to toggle presentation mode in export menu (#2660) --- frontend/components/ExportBanner.js | 11 +++++++++++ frontend/components/SlideControls.js | 12 ++++++------ frontend/editor.css | 5 +++++ 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/frontend/components/ExportBanner.js b/frontend/components/ExportBanner.js index 2cfdc24696..dff5a1fb43 100644 --- a/frontend/components/ExportBanner.js +++ b/frontend/components/ExportBanner.js @@ -108,6 +108,17 @@ export const ExportBanner = ({ notebook_id, open, onClose, notebookfile_url, not > + diff --git a/frontend/components/SlideControls.js b/frontend/components/SlideControls.js index d96e3dce9b..d1295b436c 100644 --- a/frontend/components/SlideControls.js +++ b/frontend/components/SlideControls.js @@ -37,9 +37,9 @@ export const SlideControls = () => { const height = window.innerHeight const headers = Array.from(notebook_node.querySelectorAll("pluto-output h1, pluto-output h2")) const pos = headers.map((el) => el.getBoundingClientRect()) - const edges = pos.map((rect) => rect.top + window.pageYOffset) + const edges = pos.map((rect) => rect.top + window.scrollY) - edges.push(notebook_node.getBoundingClientRect().bottom + window.pageYOffset) + edges.push(notebook_node.getBoundingClientRect().bottom + window.scrollY) const scrollPositions = headers.map((el, i) => { if (el.tagName == "H1") { @@ -58,15 +58,15 @@ export const SlideControls = () => { const go_previous_slide = (/** @type {Event} */ e) => { const positions = calculate_slide_positions(e) - const pos = positions.reverse().find((y) => y < window.pageYOffset - 10) + const pos = positions.reverse().find((y) => y < window.scrollY - 10) - if (pos) window.scrollTo(window.pageXOffset, pos) + if (pos) window.scrollTo(window.scrollX, pos) } const go_next_slide = (/** @type {Event} */ e) => { const positions = calculate_slide_positions(e) - const pos = positions.find((y) => y - 10 > window.pageYOffset) - if (pos) window.scrollTo(window.pageXOffset, pos) + const pos = positions.find((y) => y - 10 > window.scrollY) + if (pos) window.scrollTo(window.scrollX, pos) } const presenting_ref = useRef(false) diff --git a/frontend/editor.css b/frontend/editor.css index 97f5913be3..0ca807c9f4 100644 --- a/frontend/editor.css +++ b/frontend/editor.css @@ -511,6 +511,7 @@ aside#export div#container { max-width: 1000px; padding-right: 10em; margin: 0 auto; + position: relative; } header aside#export div#container { /* to prevent the div from taking up horizontal page when the export pane is closed. On small screen this causes overscroll on the right. */ @@ -732,6 +733,10 @@ aside#export button.toggle_frontmatter_edit span { background-image: url("https://cdn.jsdelivr.net/gh/ionic-team/ionicons@5.5.1/src/svg/newspaper-outline.svg"); filter: invert(1); } +aside#export button.toggle_presentation span { + background-image: url("https://cdn.jsdelivr.net/gh/ionic-team/ionicons@5.5.1/src/svg/easel-outline.svg"); + filter: invert(1); +} nav#at_the_top:after { margin-left: auto; align-self: center; From 3b375490a2e2984a9cb81f50f23a71427269a83a Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Mon, 2 Oct 2023 17:33:35 +0200 Subject: [PATCH 09/10] Featured sources: valid_until and id attribute --- frontend/components/welcome/Featured.js | 82 ++++++++++++++++++++----- 1 file changed, 66 insertions(+), 16 deletions(-) diff --git a/frontend/components/welcome/Featured.js b/frontend/components/welcome/Featured.js index 03b9e97484..6937d13241 100644 --- a/frontend/components/welcome/Featured.js +++ b/frontend/components/welcome/Featured.js @@ -94,9 +94,16 @@ const fallback_collections = [ /** * @typedef FeaturedSource - * @type {{url: String, integrity?: String}} + * @type {{ + * url: String, + * id?: String, + * integrity?: String, + * valid_until?: String + * }} */ +const get_id = (/** @type {FeaturedSource} */ source) => source?.id ?? source.url + /** * @param {{ * sources: FeaturedSource[]?, @@ -109,25 +116,51 @@ export const Featured = ({ sources, direct_html_links }) => { useEffect(() => { if (sources != null) { + set_waited_too_long(false) + set_source_data({}) + // Start downloading the sources - const promises = sources.map(async ({ url, integrity }) => { - const data = await (await fetch(new Request(url, { integrity: integrity ?? undefined }))).json() - - if (data.format_version !== "1") { - throw new Error(`Invalid format version: ${data.format_version}`) - } - - set_source_data((old) => ({ - ...old, - [url]: { - ...data, - source_url: url, - }, - })) + + const ids = Array.from(new Set(sources.map(get_id))) + + console.log(ids) + console.log("123123123213123") + + const promises = ids.map((id) => { + const sources_for_id = sources.filter((source) => get_id(source) === id) + + let result = promise_any_with_priority( + sources_for_id.map(async (source) => { + const { url, integrity, valid_until } = source + + if (valid_until != null && new Date(valid_until) < new Date()) { + throw new Error(`Source ${url} is expired with valid_until ${valid_until}`) + } + + const data = await (await fetch(new Request(url, { integrity: integrity ?? undefined }))).json() + + if (data.format_version !== "1") { + throw new Error(`Invalid format version: ${data.format_version}`) + } + + return [data, id, url] + }) + ) + + return result.then(([data, id, url]) => { + set_source_data((old) => ({ + ...old, + [id]: { + ...data, + source_url: url, + }, + })) + }) }) Promise.any(promises).catch((e) => { console.error("All featured sources failed to load: ", e) + ;(e?.errors ?? []).forEach((e) => console.error(e)) set_waited_too_long(true) }) } @@ -148,10 +181,14 @@ export const Featured = ({ sources, direct_html_links }) => { const no_data = Object.entries(source_data).length === 0 + const ids = Array.from(new Set(sources?.map(get_id) ?? [])) + + const sorted_on_source_order = ids.map((id) => source_data[id]).filter((d) => d != null) + return no_data && waited_too_long ? offline_html : html` - ${(no_data ? placeholder_data : Object.values(source_data)).map((/** @type {SourceManifest} */ data) => { + ${(no_data ? placeholder_data : sorted_on_source_order).map((/** @type {SourceManifest} */ data) => { let collections = data?.collections ?? fallback_collections return html` @@ -187,3 +224,16 @@ const collection = (/** @type {SourceManifestNotebookEntry[]} */ notebooks, /** let n = (s) => (isNaN(s) ? s : Number(s)) return /** @type {SourceManifestNotebookEntry[]} */ (_.sortBy(nbs, [(nb) => n(nb?.frontmatter?.order), "id"])) } + +/** + * Given a list promises, return promise[0].catch(() => promise[1].catch(() => promise[2]... etc)) + * @param {Promise[]} promises + * @returns {Promise} + */ +const promise_any_with_priority = (/** @type {Promise[]} */ promises, /** @type {Promise[]} */ already_rejected = []) => { + if (promises.length <= 1) { + return Promise.any([...promises, ...already_rejected]) + } else { + return promises[0].catch(() => promise_any_with_priority(promises.slice(1), [...already_rejected, promises[0]])) + } +} From a44ccc5dcd88994dc849e79f85c6fa9fe21271c3 Mon Sep 17 00:00:00 2001 From: Paul Berg Date: Sat, 7 Oct 2023 15:21:04 +0200 Subject: [PATCH 10/10] Filter on exported symbols in 1.11 (#2661) * Filter on exported symbols in 1.11 See https://github.com/JuliaLang/julia/pull/50105#issuecomment-1721111250 for context * Update PlutoRunner.jl --- src/runner/PlutoRunner.jl | 10 +++++++++- test/ExpressionExplorer.jl | 1 - 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/runner/PlutoRunner.jl b/src/runner/PlutoRunner.jl index cf252733ab..fdc891be03 100644 --- a/src/runner/PlutoRunner.jl +++ b/src/runner/PlutoRunner.jl @@ -324,9 +324,17 @@ function try_macroexpand(mod::Module, notebook_id::UUID, cell_id::UUID, expr; ca return (sanitize_expr(expr_to_save), expr_hash(expr_to_save)) end +function exported_names(mod::Module) + @static if VERSION ≥ v"1.11.0-DEV.469" + filter!(Base.Fix1(Base.isexported, mod), names(mod; all=true)) + else + names(mod) + end +end + function get_module_names(workspace_module, module_ex::Expr) try - Core.eval(workspace_module, Expr(:call, :names, module_ex)) |> Set{Symbol} + Core.eval(workspace_module, Expr(:call, exported_names, module_ex)) |> Set{Symbol} catch Set{Symbol}() end diff --git a/test/ExpressionExplorer.jl b/test/ExpressionExplorer.jl index 5ab13b83a9..aa086d6eb4 100644 --- a/test/ExpressionExplorer.jl +++ b/test/ExpressionExplorer.jl @@ -805,7 +805,6 @@ end (" 🍕🍕", (6, 10), (3, 5)), # a 🍕 is two UTF16 codeunits ] for (s, (start_byte, end_byte), (from, to)) in tests - @show s @test PlutoRunner.map_byte_range_to_utf16_codepoints(s, start_byte, end_byte) == (from, to) end end