From 45be7c15a063b65d0be8f3cb15b3fdf6e5ed83fc Mon Sep 17 00:00:00 2001 From: "Sergio A. Vargas" Date: Sun, 11 Aug 2024 03:00:33 -0500 Subject: [PATCH 1/4] Tidy up frontend (#2987) Co-authored-by: Fons van der Plas --- frontend/components/CellInput.js | 290 +++++------------- frontend/components/CellOutput.js | 6 +- frontend/components/ErrorMessage.js | 4 +- frontend/editor.css | 60 ++-- frontend/{ => fonts}/alegreya.css | 0 frontend/{ => fonts}/juliamono.css | 0 frontend/{ => fonts}/vollkorn.css | 0 frontend/highlightjs.css | 22 +- frontend/index.css | 14 +- frontend/{dark_color.css => themes/dark.css} | 89 +++--- .../{light_color.css => themes/light.css} | 82 ++--- frontend/treeview.css | 6 +- 12 files changed, 222 insertions(+), 351 deletions(-) rename frontend/{ => fonts}/alegreya.css (100%) rename frontend/{ => fonts}/juliamono.css (100%) rename frontend/{ => fonts}/vollkorn.css (100%) rename frontend/{dark_color.css => themes/dark.css} (89%) rename frontend/{light_color.css => themes/light.css} (82%) diff --git a/frontend/components/CellInput.js b/frontend/components/CellInput.js index 91065a7b9b..06e63c9d75 100644 --- a/frontend/components/CellInput.js +++ b/frontend/components/CellInput.js @@ -94,231 +94,103 @@ window.PLUTO_TOGGLE_CM_AUTOCOMPLETE_ON_TYPE = (val = !ENABLE_CM_AUTOCOMPLETE_ON_ window.location.reload() } -export const pluto_syntax_colors = HighlightStyle.define( - [ - /* The following three need a specific version of the julia parser, will add that later (still messing with it 😈) */ - // Symbol - // { tag: tags.controlKeyword, color: "var(--cm-keyword-color)", fontWeight: 700 }, - - { tag: tags.propertyName, color: "var(--cm-property-color)" }, - { tag: tags.unit, color: "var(--cm-tag-color)" }, - { tag: tags.literal, color: "var(--cm-builtin-color)", fontWeight: 700 }, - { tag: tags.macroName, color: "var(--cm-macro-color)", fontWeight: 700 }, - - // I (ab)use `special(brace)` for interpolations. - // lang-javascript does the same so I figure it is "best practice" πŸ˜… - { tag: tags.special(tags.brace), color: "var(--cm-macro-color)", fontWeight: 700 }, - - // `nothing` I guess... Any others? - { - tag: tags.standard(tags.variableName), - color: "var(--cm-builtin-color)", - fontWeight: 700, - }, - - { tag: tags.bool, color: "var(--cm-builtin-color)", fontWeight: 700 }, - - { tag: tags.keyword, color: "var(--cm-keyword-color)" }, - { tag: tags.comment, color: "var(--cm-comment-color)", fontStyle: "italic" }, - { tag: tags.atom, color: "var(--cm-atom-color)" }, - { tag: tags.number, color: "var(--cm-number-color)" }, - // { tag: tags.property, color: "#48b685" }, - // { tag: tags.attribute, color: "#48b685" }, - { tag: tags.keyword, color: "var(--cm-keyword-color)" }, - { tag: tags.string, color: "var(--cm-string-color)" }, - { tag: tags.variableName, color: "var(--cm-var-color)", fontWeight: 700 }, - // { tag: tags.variable2, color: "#06b6ef" }, - { tag: tags.typeName, color: "var(--cm-type-color)", fontStyle: "italic" }, - { tag: tags.typeOperator, color: "var(--cm-type-color)", fontStyle: "italic" }, - { tag: tags.bracket, color: "var(--cm-bracket-color)" }, - { tag: tags.brace, color: "var(--cm-bracket-color)" }, - { tag: tags.tagName, color: "var(--cm-tag-color)" }, - { tag: tags.link, color: "var(--cm-link-color)" }, - { - tag: tags.invalid, - color: "var(--cm-error-color)", - background: "var(--cm-error-bg-color)", - }, - ], +const common_style_tags = [ + { tag: tags.comment, color: "var(--cm-color-comment)", fontStyle: "italic", filter: "none" }, + { tag: tags.keyword, color: "var(--cm-color-keyword)" }, + { tag: tags.variableName, color: "var(--cm-color-var)", fontWeight: 700 }, + { tag: tags.typeName, color: "var(--cm-color-type)", fontStyle: "italic" }, + { tag: tags.typeOperator, color: "var(--cm-color-type)", fontStyle: "italic" }, + { tag: tags.tagName, color: "var(--cm-color-tag)" }, // JS + { tag: tags.propertyName, color: "var(--cm-color-property)" }, + // TODO: tags.labelName + { tag: tags.macroName, color: "var(--cm-color-macro)", fontWeight: 700 }, + { tag: tags.string, color: "var(--cm-color-string)" }, + // TODO: tags.character + { tag: tags.number, color: "var(--cm-color-number)" }, + { tag: tags.bool, color: "var(--cm-color-builtin)", fontWeight: 700 }, + // TODO: tags.escape + // TODO: tags.self, tags.null + { tag: tags.atom, color: "var(--cm-color-atom)" }, + { tag: tags.unit, color: "var(--cm-color-tag)" }, // TODO: Remove + // TODO? tags.operator + { tag: tags.bracket, color: "var(--cm-color-bracket)" }, + { tag: tags.special(tags.brace), color: "var(--cm-color-macro)", fontWeight: 700 }, // interp +] + +export const pluto_syntax_colors_julia = HighlightStyle.define( + common_style_tags, { - all: { color: `var(--cm-editor-text-color)` }, + all: { color: `var(--cm-color-editor-text)` }, scope: julia_andrey().language, } ) export const pluto_syntax_colors_javascript = HighlightStyle.define( - [ - // SAME AS JULIA: - { tag: tags.propertyName, color: "var(--cm-property-color)" }, - { tag: tags.unit, color: "var(--cm-tag-color)" }, - { tag: tags.literal, color: "var(--cm-builtin-color)", fontWeight: 700 }, - { tag: tags.macroName, color: "var(--cm-macro-color)", fontWeight: 700 }, - - // `nothing` I guess... Any others? - { - tag: tags.standard(tags.variableName), - color: "var(--cm-builtin-color)", - fontWeight: 700, - }, - - { tag: tags.bool, color: "var(--cm-builtin-color)", fontWeight: 700 }, - - { tag: tags.keyword, color: "var(--cm-keyword-color)" }, - { tag: tags.atom, color: "var(--cm-atom-color)" }, - { tag: tags.number, color: "var(--cm-number-color)" }, - // { tag: tags.property, color: "#48b685" }, - // { tag: tags.attribute, color: "#48b685" }, - { tag: tags.keyword, color: "var(--cm-keyword-color)" }, - { tag: tags.string, color: "var(--cm-string-color)" }, - { tag: tags.variableName, color: "var(--cm-var-color)", fontWeight: 700 }, - // { tag: tags.variable2, color: "#06b6ef" }, - { tag: tags.typeName, color: "var(--cm-type-color)", fontStyle: "italic" }, - { tag: tags.typeOperator, color: "var(--cm-type-color)", fontStyle: "italic" }, - { tag: tags.bracket, color: "var(--cm-bracket-color)" }, - { tag: tags.brace, color: "var(--cm-bracket-color)" }, - { tag: tags.tagName, color: "var(--cm-tag-color)" }, - { tag: tags.link, color: "var(--cm-link-color)" }, - { - tag: tags.invalid, - color: "var(--cm-error-color)", - background: "var(--cm-error-bg-color)", - }, - - // JAVASCRIPT SPECIFIC - { tag: tags.comment, color: "var(--cm-comment-color)", fontStyle: "italic", filter: "none" }, - ], + common_style_tags, { + all: { color: `var(--cm-color-editor-text)`, filter: `contrast(0.5)` }, scope: javascriptLanguage, - all: { - color: `var(--cm-editor-text-color)`, - filter: `contrast(0.5)`, - }, } ) export const pluto_syntax_colors_python = HighlightStyle.define( - [ - // SAME AS JULIA: - { tag: tags.propertyName, color: "var(--cm-property-color)" }, - { tag: tags.unit, color: "var(--cm-tag-color)" }, - { tag: tags.literal, color: "var(--cm-builtin-color)", fontWeight: 700 }, - { tag: tags.macroName, color: "var(--cm-macro-color)", fontWeight: 700 }, - - // `nothing` I guess... Any others? - { - tag: tags.standard(tags.variableName), - color: "var(--cm-builtin-color)", - fontWeight: 700, - }, - - { tag: tags.bool, color: "var(--cm-builtin-color)", fontWeight: 700 }, - - { tag: tags.keyword, color: "var(--cm-keyword-color)" }, - { tag: tags.comment, color: "var(--cm-comment-color)", fontStyle: "italic" }, - { tag: tags.atom, color: "var(--cm-atom-color)" }, - { tag: tags.number, color: "var(--cm-number-color)" }, - // { tag: tags.property, color: "#48b685" }, - // { tag: tags.attribute, color: "#48b685" }, - { tag: tags.keyword, color: "var(--cm-keyword-color)" }, - { tag: tags.string, color: "var(--cm-string-color)" }, - { tag: tags.variableName, color: "var(--cm-var-color)", fontWeight: 700 }, - // { tag: tags.variable2, color: "#06b6ef" }, - { tag: tags.typeName, color: "var(--cm-type-color)", fontStyle: "italic" }, - { tag: tags.typeOperator, color: "var(--cm-type-color)", fontStyle: "italic" }, - { tag: tags.bracket, color: "var(--cm-bracket-color)" }, - { tag: tags.brace, color: "var(--cm-bracket-color)" }, - { tag: tags.tagName, color: "var(--cm-tag-color)" }, - { tag: tags.link, color: "var(--cm-link-color)" }, - { - tag: tags.invalid, - color: "var(--cm-error-color)", - background: "var(--cm-error-bg-color)", - }, - - // PYTHON SPECIFIC - ], + common_style_tags, { + all: { color: `var(--cm-color-editor-text)`, filter: `contrast(0.5)` }, scope: pythonLanguage, - all: { - color: "var(--cm-editor-text-color)", - filter: `contrast(0.5)`, - }, } ) -export const pluto_syntax_colors_css = HighlightStyle.define( - [ - { tag: tags.propertyName, color: "var(--cm-css-accent-color)", fontWeight: 700 }, - { tag: tags.variableName, color: "var(--cm-css-accent-color)", fontWeight: 700 }, - { tag: tags.definitionOperator, color: "var(--cm-css-color)" }, - { tag: tags.keyword, color: "var(--cm-css-color)" }, - { tag: tags.modifier, color: "var(--cm-css-accent-color)" }, - { tag: tags.punctuation, opacity: 0.5 }, - { tag: tags.literal, color: "var(--cm-css-color)" }, - // { tag: tags.unit, color: "var(--cm-css-accent-color)" }, - { tag: tags.tagName, color: "var(--cm-css-color)", fontWeight: 700 }, - { tag: tags.className, color: "var(--cm-css-why-doesnt-codemirror-highlight-all-the-text-aaa)" }, - { tag: tags.constant(tags.className), color: "var(--cm-css-why-doesnt-codemirror-highlight-all-the-text-aaa)" }, - - // Comment from julia - { tag: tags.comment, color: "var(--cm-comment-color)", fontStyle: "italic" }, - ], - { - scope: cssLanguage, - all: { color: "var(--cm-css-color)" }, - } -) - -export const pluto_syntax_colors_html = HighlightStyle.define( - [ - { tag: tags.tagName, color: "var(--cm-html-accent-color)", fontWeight: 600 }, - { tag: tags.attributeName, color: "var(--cm-html-accent-color)", fontWeight: 600 }, - { tag: tags.attributeValue, color: "var(--cm-html-accent-color)" }, - { tag: tags.angleBracket, color: "var(--cm-html-accent-color)", fontWeight: 600, opacity: 0.7 }, - { tag: tags.content, color: "var(--cm-html-color)", fontWeight: 400 }, - { tag: tags.documentMeta, color: "var(--cm-html-accent-color)" }, - { tag: tags.comment, color: "var(--cm-comment-color)", fontStyle: "italic" }, - ], - { - scope: htmlLanguage, - all: { - color: "var(--cm-html-color)", - }, - } -) - -// https://github.com/codemirror/lang-markdown/blob/main/src/markdown.ts -export const pluto_syntax_colors_markdown = HighlightStyle.define( - [ - { tag: tags.content, color: "var(--cm-md-color)" }, - { tag: tags.quote, color: "var(--cm-md-color)" }, - { tag: tags.link, textDecoration: "underline" }, - { tag: tags.url, color: "var(--cm-md-color)", textDecoration: "none" }, - { tag: tags.emphasis, fontStyle: "italic" }, - { tag: tags.strong, fontWeight: "bolder" }, - - { tag: tags.heading, color: "var(--cm-md-color)", fontWeight: 700 }, - { - tag: tags.comment, - color: "var(--cm-comment-color)", - fontStyle: "italic", - }, - { - // These are all the things you won't see in the result: - // `-` bullet points, the `#` for headers, the `>` with quoteblocks. - tag: tags.processingInstruction, - color: "var(--cm-md-accent-color) !important", - opacity: "0.5", - }, - { tag: tags.monospace, color: "var(--cm-md-accent-color)" }, - ], - { - scope: markdownLanguage, - all: { - color: "var(--cm-md-color)", - }, - } -) +export const pluto_syntax_colors_css = HighlightStyle.define([ + { tag: tags.comment, color: "var(--cm-color-comment)", fontStyle: "italic" }, + { tag: tags.variableName, color: "var(--cm-color-css-accent)", fontWeight: 700 }, + { tag: tags.propertyName, color: "var(--cm-color-css-accent)", fontWeight: 700 }, + { tag: tags.tagName, color: "var(--cm-color-css)", fontWeight: 700 }, + //{ tag: tags.className, color: "var(--cm-css-why-doesnt-codemirror-highlight-all-the-text-aaa)" }, + //{ tag: tags.constant(tags.className), color: "var(--cm-css-why-doesnt-codemirror-highlight-all-the-text-aaa)" }, + { tag: tags.definitionOperator, color: "var(--cm-color-css)" }, + { tag: tags.keyword, color: "var(--cm-color-css)" }, + { tag: tags.modifier, color: "var(--cm-color-css-accent)" }, + { tag: tags.literal, color: "var(--cm-color-css)" }, + // { tag: tags.unit, color: "var(--cm-color-css-accent)" }, + { tag: tags.punctuation, opacity: 0.5 }, +], { + scope: cssLanguage, + all: { color: "var(--cm-color-css)" }, +}) + +export const pluto_syntax_colors_html = HighlightStyle.define([ + { tag: tags.comment, color: "var(--cm-color-comment)", fontStyle: "italic" }, + { tag: tags.content, color: "var(--cm-color-html)", fontWeight: 400 }, + { tag: tags.tagName, color: "var(--cm-color-html-accent)", fontWeight: 600 }, + { tag: tags.documentMeta, color: "var(--cm-color-html-accent)" }, + { tag: tags.attributeName, color: "var(--cm-color-html-accent)", fontWeight: 600 }, + { tag: tags.attributeValue, color: "var(--cm-color-html-accent)" }, + { tag: tags.angleBracket, color: "var(--cm-color-html-accent)", fontWeight: 600, opacity: 0.7 }, +], { + all: { color: "var(--cm-color-html)" }, + scope: htmlLanguage, +}) + +// https://github.com/lezer-parser/markdown/blob/d4de2b03180ced4610bad9cef0ad3a805c43b63a/src/markdown.ts#L1890 +export const pluto_syntax_colors_markdown = HighlightStyle.define([ + { tag: tags.comment, color: "var(--cm-color-comment)", fontStyle: "italic" }, + { tag: tags.content, color: "var(--cm-color-md)" }, + { tag: tags.heading, color: "var(--cm-color-md)", fontWeight: 700 }, + // TODO? tags.list + { tag: tags.quote, color: "var(--cm-color-md)" }, + { tag: tags.emphasis, fontStyle: "italic" }, + { tag: tags.strong, fontWeight: "bolder" }, + { tag: tags.link, textDecoration: "underline" }, + { tag: tags.url, color: "var(--cm-color-md)", textDecoration: "none" }, + { tag: tags.monospace, color: "var(--cm-color-md-accent)" }, + + // Marks: `-` for lists, `#` for headers, etc. + { tag: tags.processingInstruction, color: "var(--cm-color-md-accent) !important", opacity: "0.5" }, +], { + all: { color: "var(--cm-color-md)" }, + scope: markdownLanguage, +}) const getValue6 = (/** @type {EditorView} */ cm) => cm.state.doc.toString() const setValue6 = (/** @type {EditorView} */ cm, value) => @@ -699,7 +571,7 @@ export const CellInput = ({ pkgBubblePlugin({ pluto_actions, notebook_id_ref }), ScopeStateField, - syntaxHighlighting(pluto_syntax_colors), + syntaxHighlighting(pluto_syntax_colors_julia), syntaxHighlighting(pluto_syntax_colors_html), syntaxHighlighting(pluto_syntax_colors_markdown), syntaxHighlighting(pluto_syntax_colors_javascript), diff --git a/frontend/components/CellOutput.js b/frontend/components/CellOutput.js index 5ee73add66..d274fea663 100644 --- a/frontend/components/CellOutput.js +++ b/frontend/components/CellOutput.js @@ -21,7 +21,7 @@ import register from "../imports/PreactCustomElement.js" import { EditorState, EditorView, defaultHighlightStyle, syntaxHighlighting } from "../imports/CodemirrorPlutoSetup.js" -import { pluto_syntax_colors, ENABLE_CM_MIXED_PARSER } from "./CellInput.js" +import { pluto_syntax_colors_julia, ENABLE_CM_MIXED_PARSER } from "./CellInput.js" import hljs from "../imports/highlightjs.js" import { julia_mixed } from "./CellInput/mixedParsers.js" @@ -29,7 +29,7 @@ import { julia_andrey } from "../imports/CodemirrorPlutoSetup.js" import { SafePreviewSanitizeMessage } from "./SafePreviewUI.js" const prettyAssignee = (assignee) => - assignee && assignee.startsWith("const ") ? html`const ${assignee.slice(6)}` : assignee + assignee && assignee.startsWith("const ") ? html`const ${assignee.slice(6)}` : assignee export class CellOutput extends Component { constructor() { @@ -676,7 +676,7 @@ export let highlight = (code_element, language) => { .replace(/Main.workspace#(\d+)/, 'Main.var"workspace#$1"'), extensions: [ - syntaxHighlighting(pluto_syntax_colors), + syntaxHighlighting(pluto_syntax_colors_julia), syntaxHighlighting(defaultHighlightStyle, { fallback: true }), EditorState.tabSize.of(4), // TODO Other languages possibly? diff --git a/frontend/components/ErrorMessage.js b/frontend/components/ErrorMessage.js index 5f6c4d8be2..9ca2cbbb33 100644 --- a/frontend/components/ErrorMessage.js +++ b/frontend/components/ErrorMessage.js @@ -1,11 +1,9 @@ import { cl } from "../common/ClassTable.js" import { PlutoActionsContext } from "../common/PlutoContext.js" -import { EditorState, EditorView, julia_andrey, lineNumbers, syntaxHighlighting } from "../imports/CodemirrorPlutoSetup.js" import { html, useContext, useEffect, useLayoutEffect, useRef, useState } from "../imports/Preact.js" -import { pluto_syntax_colors } from "./CellInput.js" import { highlight } from "./CellOutput.js" -import { Editor } from "./Editor.js" import { PkgTerminalView } from "./PkgTerminalView.js" +import _ from "../imports/lodash.js" const extract_cell_id = (/** @type {string} */ file) => { const sep_index = file.indexOf("#==#") diff --git a/frontend/editor.css b/frontend/editor.css index 4a3849125c..46a8c2c347 100644 --- a/frontend/editor.css +++ b/frontend/editor.css @@ -13,16 +13,16 @@ @import url("https://cdn.jsdelivr.net/npm/@fontsource/alegreya-sans@5.0.12/400-italic.css"); @import url("https://cdn.jsdelivr.net/npm/@fontsource/alegreya-sans@5.0.12/500-italic.css"); @import url("https://cdn.jsdelivr.net/npm/@fontsource/alegreya-sans@5.0.12/700-italic.css"); */ -@import url("./alegreya.css"); +@import url("./fonts/alegreya.css"); -@import url("./juliamono.css"); -@import url("./vollkorn.css"); +@import url("./fonts/juliamono.css"); +@import url("./fonts/vollkorn.css"); /* @import url("https://fonts.googleapis.com/css2?family=Lato&display=swap"); */ @import url("https://cdn.jsdelivr.net/npm/@fontsource/lato@4.4.5/400.css"); @import url("https://cdn.jsdelivr.net/npm/@fontsource/lato@4.4.5/400-italic.css"); -@import url("./light_color.css"); -@import url("./dark_color.css"); +@import url("./themes/light.css"); +@import url("./themes/dark.css"); @import url("./featured-card.css"); @@ -3280,7 +3280,7 @@ button.floating_back_button { /* CODEMIRROR HINTS */ .cm-editor .cm-tooltip { - border: 1px solid var(--cm-editor-tooltip-border-color); + border: 1px solid var(--cm-color-editor-tooltip-border); box-shadow: 3px 3px 4px rgb(0 0 0 / 20%); border-radius: 4px; } @@ -3315,8 +3315,8 @@ pluto-input .cm-editor .cm-tooltip.cm-tooltip-autocomplete > ul > li { } .cm-editor .cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected] { - color: var(--cm-editor-li-aria-selected-color); - background: var(--cm-editor-li-aria-selected-bg-color); + color: var(--cm-color-editor-li-aria-selected); + background: var(--cm-color-editor-li-aria-selected-bg); } .cm-editor .cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected] .cm-completionLabel { border-color: transparent; @@ -3330,7 +3330,7 @@ pluto-input .cm-editor .cm-tooltip.cm-tooltip-autocomplete > ul > li { } .cm-editor .cm-tooltip.cm-tooltip-autocomplete li.c_notexported { - color: var(--cm-editor-li-notexported-color); + color: var(--cm-color-editor-li-notexported); } .cm-editor .cm-completionIcon { @@ -3367,7 +3367,7 @@ Based on "ParaΓ­so (Light)" by Jan T. Sott: .cm-editor .cm-tooltip.cm-tooltip-autocomplete li.c_from_notebook .cm-completionLabel { font-weight: bold; text-decoration: underline; - text-decoration-color: var(--cm-clickable-underline); + text-decoration-color: var(--cm-color-clickable-underline); text-decoration-thickness: 3px; text-decoration-skip-ink: none; } @@ -3430,7 +3430,7 @@ pluto-input .cm-editor .cm-content { .cm-editor { background: var(--code-background); - color: var(--cm-editor-text-color); + color: var(--cm-color-editor-text); } .cm-editor.cm-focused:not(.__) { outline: unset; @@ -3450,7 +3450,7 @@ pluto-input .cm-editor .cm-content { pluto-cell.code_differs .cm-editor .cm-gutters { /* background: hsla(46, 70%, 88%, 1); */ - background-color: var(--cm-code-differs-gutters-color); + background-color: var(--cm-color-code-differs-gutters); } /* We show a small dot instead of line number, until you hover. */ @@ -3460,13 +3460,13 @@ pluto-cell.code_differs .cm-editor .cm-gutters { .cm-editor .cm-lineNumbers .cm-gutterElement::after { content: "β‹…"; font-size: 0.75rem; - color: var(--cm-line-numbers-color); + color: var(--cm-color-line-numbers); position: absolute; right: 3px; pointer-events: none; } .cm-editor .cm-lineNumbers .cm-gutterElement:hover { - color: var(--cm-line-numbers-color); + color: var(--cm-color-line-numbers); } .cm-editor .cm-lineNumbers .cm-gutterElement:hover::after { color: transparent; @@ -3475,7 +3475,7 @@ pluto-cell.code_differs .cm-editor .cm-gutters { /* Disabling this feature in two cases: */ /* Case 1: The cell input is in focus */ /* pluto-input:focus-within .cm-editor .cm-lineNumbers .cm-gutterElement { - color: var(--cm-line-numbers-color); + color: var(--cm-color-line-numbers); } pluto-input:focus-within .cm-editor .cm-lineNumbers .cm-gutterElement::after { color: transparent; @@ -3483,7 +3483,7 @@ pluto-input:focus-within .cm-editor .cm-lineNumbers .cm-gutterElement::after { */ pluto-cell.errored .cm-editor .cm-lineNumbers .cm-gutterElement { - color: var(--cm-line-numbers-color); + color: var(--cm-color-line-numbers); } pluto-cell.errored .cm-editor .cm-lineNumbers .cm-gutterElement::after { color: transparent; @@ -3491,7 +3491,7 @@ pluto-cell.errored .cm-editor .cm-lineNumbers .cm-gutterElement::after { /* Case 2: Print */ @media print { .cm-editor .cm-lineNumbers .cm-gutterElement { - color: var(--cm-line-numbers-color) !important; + color: var(--cm-color-line-numbers) !important; } .cm-editor .cm-lineNumbers .cm-gutterElement::after { color: transparent !important; @@ -3499,21 +3499,21 @@ pluto-cell.errored .cm-editor .cm-lineNumbers .cm-gutterElement::after { } .cm-completionIcon-c_Number::before { - color: var(--cm-number-color); + color: var(--cm-color-number); } .cm-completionIcon-c_String::before, .cm-completionIcon-completion_path::before, .cm-completionIcon-completion_dict::before { - color: var(--cm-string-color); + color: var(--cm-color-string); } .cm-completionIcon-completion_property::before { - color: var(--cm-property-color); + color: var(--cm-color-property); } .cm-completionIcon-completion_keyword::before { - color: var(--cm-keyword-color); + color: var(--cm-color-keyword); } li.completion_keyword_argument .cm-completionLabel { @@ -3521,30 +3521,30 @@ li.completion_keyword_argument .cm-completionLabel { font-weight: bold; } .cm-completionIcon-completion_keyword_argument::before { - color: var(--cm-number-color); + color: var(--cm-color-number); } .cm-completionIcon-c_Any::before, pluto-output > assignee, pluto-popup code.auto_disabled_variable { - color: var(--cm-var-color) !important; + color: var(--cm-color-var) !important; font-weight: 700; } .cm-completionIcon-c_Function::before { - color: var(--cm-function-color); + color: var(--cm-color-function); } .cm-completionIcon-c_Macro::before { - color: var(--cm-macro-color); + color: var(--cm-color-macro); } .cm-completionIcon-c_Array::before { - color: var(--cm-bracket-color); + color: var(--cm-color-bracket); } .cm-completionIcon-c_package::before, .cm-completionIcon-c_Module::before { - color: var(--cm-link-color); + color: var(--cm-color-link); } .cm-editor .cm-activeLine { @@ -3569,14 +3569,14 @@ pluto-popup code.auto_disabled_variable { color: unset; } pluto-input:focus-within .cm-editor .cm-matchingBracket { - color: var(--cm-matchingBracket-color) !important; + color: var(--cm-color-matchingBracket) !important; font-weight: 700; - background-color: var(--cm-matchingBracket-bg-color); + background-color: var(--cm-color-matchingBracket-bg); border-radius: 2px; } .cm-editor .cm-placeholder { - color: var(--cm-placeholder-text-color); + color: var(--cm-color-placeholder-text); font-style: italic; } diff --git a/frontend/alegreya.css b/frontend/fonts/alegreya.css similarity index 100% rename from frontend/alegreya.css rename to frontend/fonts/alegreya.css diff --git a/frontend/juliamono.css b/frontend/fonts/juliamono.css similarity index 100% rename from frontend/juliamono.css rename to frontend/fonts/juliamono.css diff --git a/frontend/vollkorn.css b/frontend/fonts/vollkorn.css similarity index 100% rename from frontend/vollkorn.css rename to frontend/fonts/vollkorn.css diff --git a/frontend/highlightjs.css b/frontend/highlightjs.css index 922c4cdd0c..cc932fc77b 100644 --- a/frontend/highlightjs.css +++ b/frontend/highlightjs.css @@ -7,34 +7,34 @@ code.hljs { padding: 3px 5px; } .hljs { - color: var(--cm-editor-text-color); + color: var(--cm-color-editor-text); } .hljs-comment, .hljs-quote { - color: var(--cm-comment-color); + color: var(--cm-color-comment); font-style: italic; } .hljs-doctag, .hljs-formula, .hljs-keyword { - color: var(--cm-keyword-color); + color: var(--cm-color-keyword); } .hljs-deletion, .hljs-name, .hljs-section, .hljs-selector-tag, .hljs-subst { - color: var(--cm-var2-color); + color: var(--cm-color-var2); } .hljs-literal { - color: var(--cm-builtin-color); + color: var(--cm-color-builtin); } .hljs-addition, .hljs-attribute, .hljs-meta .hljs-string, .hljs-regexp, .hljs-string { - color: var(--cm-string-color); + color: var(--cm-color-string); } .hljs-attr, .hljs-selector-attr, @@ -43,26 +43,26 @@ code.hljs { .hljs-template-variable, .hljs-type, .hljs-variable { - color: var(--cm-var-color); + color: var(--cm-color-var); } .hljs-number { - color: var(--cm-number-color); + color: var(--cm-color-number); } .hljs-bullet, .hljs-link, .hljs-selector-id, .hljs-symbol, .hljs-title { - color: var(--cm-link-color); + color: var(--cm-color-link); } .hljs-meta { - color: var(--cm-macro-color); + color: var(--cm-color-macro); font-weight: 700; } .hljs-built_in, .hljs-class .hljs-title, .hljs-title.class_ { - color: var(--cm-var2-color); + color: var(--cm-color-var2); } .hljs-emphasis { font-style: italic; diff --git a/frontend/index.css b/frontend/index.css index d4c9d62865..a6cc9ac6d3 100644 --- a/frontend/index.css +++ b/frontend/index.css @@ -1,11 +1,11 @@ @import url("https://cdn.jsdelivr.net/npm/@fontsource/roboto-mono@4.4.5/400.css"); @import url("https://cdn.jsdelivr.net/npm/@fontsource/roboto-mono@4.4.5/400-italic.css"); -@import url("vollkorn.css"); -@import url("juliamono.css"); +@import url("./fonts/vollkorn.css"); +@import url("./fonts/juliamono.css"); -@import url("light_color.css"); -@import url("dark_color.css"); +@import url("./themes/light.css"); +@import url("./themes/dark.css"); @import url("featured-card.css"); @@ -160,7 +160,7 @@ pluto-filepicker button:disabled { } .cm-editor .cm-tooltip { - border: 1px solid var(--cm-editor-tooltip-border-color); + border: 1px solid var(--cm-color-editor-tooltip-border); box-shadow: 3px 3px 4px rgb(0 0 0 / 20%); border-radius: 4px; } @@ -190,8 +190,8 @@ pluto-filepicker button:disabled { } .cm-editor .cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected] { - color: var(--cm-editor-li-aria-selected-color); - background: var(--cm-editor-li-aria-selected-bg-color); + color: var(--cm-color-editor-li-aria-selected); + background: var(--cm-color-editor-li-aria-selected-bg); } .cm-editor .cm-completionIcon { diff --git a/frontend/dark_color.css b/frontend/themes/dark.css similarity index 89% rename from frontend/dark_color.css rename to frontend/themes/dark.css index 701aa5ac19..92ec058ecd 100644 --- a/frontend/dark_color.css +++ b/frontend/themes/dark.css @@ -2,6 +2,8 @@ :root { --image-filters: invert(1) hue-rotate(180deg) contrast(0.8); --out-of-focus-opacity: 0.5; + + /* Color scheme */ --main-bg-color: hsl(0deg 0% 12%); --rule-color: rgba(255, 255, 255, 0.15); --kbd-border-color: #222222; @@ -12,6 +14,7 @@ /* Cells */ --normal-cell: 100, 100, 100; + /* --code-differs */ --error-color: 255, 125, 125; --normal-cell-color: rgba(var(--normal-cell), 0.2); --dark-normal-cell-color: rgba(var(--normal-cell), 0.4); @@ -56,6 +59,7 @@ --jl-danger-accent-color: rgb(255, 117, 98); --jl-debug-color: hsl(288deg 33% 27%); --jl-debug-accent-color: hsl(283deg 59% 69%); + /* --footnote-border-color */ --table-border-color: rgba(255, 255, 255, 0.2); --table-bg-hover-color: rgba(193, 192, 235, 0.15); --pluto-tree-color: rgb(209 207 207 / 61%); @@ -77,7 +81,6 @@ --pluto-logs-progress-fill: #5f7f5b; --pluto-logs-progress-bg: #3d3d3d; --pluto-logs-progress-border: hsl(210deg 35% 72%); - --pluto-logs-info-color: #484848; --pluto-logs-info-accent-color: inherit; --pluto-logs-warn-color: rgb(80 76 38); @@ -106,6 +109,7 @@ /*loading bar*/ --loading-grad-color-1: #a9d4f1; --loading-grad-color-2: #d0d4d7; + /*saveall container*/ --overlay-button-bg: #2c2c2c; --overlay-button-border: #9e9e9e70; @@ -154,7 +158,6 @@ --helpbox-text-color: rgb(230, 230, 230); --code-section-bg-color: rgb(44, 44, 44); --code-section-border-color: #555a64; - --process-item-bg: #443d44; --process-busy: #ffcd70; --process-finished: hsl(126deg 30% 60%); @@ -175,40 +178,49 @@ --undo-delete-box-shadow-color: rgba(213, 213, 214, 0.2); /*codemirror hints*/ - --cm-editor-tooltip-border-color: rgba(0, 0, 0, 0.2); - --cm-editor-li-aria-selected-bg-color: #3271e7; - --cm-editor-li-aria-selected-color: white; - --cm-editor-li-notexported-color: rgba(255, 255, 255, 0.5); + --cm-color-editor-tooltip-border: rgba(0, 0, 0, 0.2); + --cm-color-editor-li-aria-selected-bg: #3271e7; + --cm-color-editor-li-aria-selected: white; + --cm-color-editor-li-notexported: rgba(255, 255, 255, 0.5); --code-background: hsl(222deg 16% 19%); - --cm-code-differs-gutters-color: rgb(235 213 28 / 11%); - --cm-line-numbers-color: #8d86875e; + --cm-color-code-differs-gutters: rgb(235 213 28 / 11%); + --cm-color-line-numbers: #8d86875e; --cm-selection-background: hsl(215deg 64% 59% / 48%); --cm-selection-background-blurred: hsl(215deg 0% 59% / 48%); --cm-highlighted: #cbceb629; /* code highlighting */ - --cm-editor-text-color: #ffe9fc; - --cm-comment-color: #e96ba8; - --cm-atom-color: hsl(8deg 72% 62%); - --cm-number-color: hsl(271deg 45% 64%); - --cm-property-color: #f99b15; - --cm-keyword-color: #ff7a6f; - --cm-string-color: hsl(20deg 69% 59%); - --cm-var-color: #afb7d3; - --cm-var2-color: #06b6ef; - --cm-macro-color: #82b38b; - --cm-builtin-color: #5e7ad3; - --cm-function-color: #f99b15; - --cm-type-color: hsl(51deg 32% 44%); - --cm-bracket-color: #a2a273; - --cm-tag-color: #ef6155; - --cm-link-color: #815ba4; - --cm-error-bg-color: #ef6155; - --cm-error-color: #f7f7f7; - --cm-matchingBracket-color: white; - --cm-matchingBracket-bg-color: #c58c237a; - --cm-placeholder-text-color: rgb(255 255 255 / 20%); - --cm-clickable-underline: #5d5f70; + --cm-color-editor-text: #ffe9fc; + --cm-color-comment: #e96ba8; + --cm-color-atom: hsl(8deg 72% 62%); + --cm-color-number: hsl(271deg 45% 64%); + --cm-color-property: #f99b15; + --cm-color-keyword: #ff7a6f; + --cm-color-string: hsl(20deg 69% 59%); + --cm-color-var: #afb7d3; + --cm-color-var2: #06b6ef; + --cm-color-macro: #82b38b; + --cm-color-builtin: #5e7ad3; + --cm-color-function: #f99b15; + --cm-color-type: hsl(51deg 32% 44%); + --cm-color-bracket: #a2a273; + --cm-color-tag: #ef6155; + --cm-color-link: #815ba4; + --cm-color-error-bg: #ef6155; + --cm-color-error: #f7f7f7; + --cm-color-matchingBracket: white; + --cm-color-matchingBracket-bg: #c58c237a; + --cm-color-placeholder-text: rgb(255 255 255 / 20%); + --cm-color-clickable-underline: #5d5f70; + + /* Mixed parsers */ + --cm-color-html: #00ab85; + --cm-color-html-accent: #00e7b4; + --cm-color-css: #ebd073; + --cm-color-css-accent: #fffed2; + --cm-css-why-doesnt-codemirror-highlight-all-the-text-aaa: #ffffea; + --cm-color-md: #a2c9d5; + --cm-color-md-accent: #00a9d1; /*autocomplete menu*/ --autocomplete-menu-bg-color: var(--input-context-menu-bg-color); @@ -217,6 +229,7 @@ --index-text-color: rgb(199, 199, 199); --index-light-text-color: rgb(199, 199, 199); --index-clickable-text-color: rgb(235, 235, 235); + --docs-binding-bg: #323431; --index-card-bg: #313131; --welcome-mywork-bg: var(--header-bg-color); --welcome-newnotebook-bg: rgb(68 72 102); @@ -224,25 +237,11 @@ --welcome-recentnotebook-border: #6e6e6e; --welcome-open-bg: hsl(233deg 20% 33%); --welcome-card-author-backdrop: #0000006b; - - /* docs binding */ - --docs-binding-bg: #323431; - - /* Nesed languages in codemirror! */ - --cm-html-color: #00ab85; - --cm-html-accent-color: #00e7b4; - --cm-css-color: #ebd073; - --cm-css-accent-color: #fffed2; - /* This is basically --cm-css-accent-color, but because the CSS plugin shows some characters in plain white, - this is made also a liiiitle lighter so it doesn't stand out too much against the white prefix */ - --cm-css-why-doesnt-codemirror-highlight-all-the-text-aaa: #ffffea; - --cm-md-color: #a2c9d5; - --cm-md-accent-color: #00a9d1; } @media (prefers-contrast: more) { :root { - --cm-line-numbers-color: #b3b3b3; + --cm-color-line-numbers: #b3b3b3; } } body:not(.disable_ui):not(.more-specificity) { diff --git a/frontend/light_color.css b/frontend/themes/light.css similarity index 82% rename from frontend/light_color.css rename to frontend/themes/light.css index 36fb8d22d5..c1bd8b4f03 100644 --- a/frontend/light_color.css +++ b/frontend/themes/light.css @@ -11,11 +11,11 @@ --header-border-color: rgba(0, 0, 0, 0.1); --ui-button-color: #2a2a2b; --cursor-color: black; + + /* Cells */ --normal-cell: 0, 0, 0; --code-differs: 160, 130, 28; --error-color: 240, 168, 168; - - /*Cells*/ --normal-cell-color: rgba(var(--normal-cell), 0.1); --dark-normal-cell-color: rgba(var(--normal-cell), 0.2); --selected-cell-color: rgba(40, 78, 189, 0.4); @@ -41,6 +41,7 @@ /*Pluto output styling */ --pluto-schema-types-color: rgba(0, 0, 0, 0.4); --pluto-schema-types-border-color: rgba(0, 0, 0, 0.2); + /* --pluto-dim-output-color */ --pluto-output-color: hsl(0, 0%, 25%); --pluto-output-h-color: hsl(0, 0%, 12%); --pluto-output-bg-color: white; @@ -113,6 +114,7 @@ --overlay-button-bg: #ffffff; --overlay-button-border: hsl(0 4% 91% / 1); --overlay-button-border-save: #f3f2f2; + /* --overlay-button-color */ /*input_context_menu*/ --input-context-menu-border-color: rgba(0, 0, 0, 0.1); @@ -155,7 +157,7 @@ --helpbox-notfound-search-color: rgb(139, 139, 139); --helpbox-text-color: black; --code-section-bg-color: whitesmoke; - --code-section-bg-color: #f3f3f3; + --code-section-bg-color: #f3f3f3; /* TODO: Should this be `-border-color`? */ --process-item-bg: #f2f2f2; --process-busy: #ffcd70; --process-finished: hsl(126deg 30% 60%); @@ -176,40 +178,49 @@ --undo-delete-box-shadow-color: #0083; /*codemirror hints*/ - --cm-editor-tooltip-border-color: rgba(0, 0, 0, 0.2); - --cm-editor-li-aria-selected-bg-color: #16659d; - --cm-editor-li-aria-selected-color: white; - --cm-editor-li-notexported-color: rgba(0, 0, 0, 0.5); + --cm-color-editor-tooltip-border: rgba(0, 0, 0, 0.2); + --cm-color-editor-li-aria-selected-bg: #16659d; + --cm-color-editor-li-aria-selected: white; + --cm-color-editor-li-notexported: rgba(0, 0, 0, 0.5); --code-background: hsla(46, 90%, 98%, 1); - --cm-code-differs-gutters-color: rgba(214, 172, 35, 0.2); - --cm-line-numbers-color: #8d86875e; + --cm-color-code-differs-gutters: rgba(214, 172, 35, 0.2); + --cm-color-line-numbers: #8d86875e; --cm-selection-background: hsl(214deg 100% 73% / 48%); --cm-selection-background-blurred: hsl(214deg 0% 73% / 48%); --cm-highlighted: #cbceb668; /* code highlighting */ - --cm-editor-text-color: #41323f; - --cm-comment-color: #e96ba8; - --cm-atom-color: #815ba4; - --cm-number-color: #815ba4; - --cm-property-color: #b67a48; - --cm-keyword-color: #ef6155; - --cm-string-color: #da5616; - --cm-var-color: #5668a4; - --cm-macro-color: #5c8c5f; - --cm-var2-color: #37768a; - --cm-builtin-color: #5e7ad3; - --cm-function-color: #cc80ac; - --cm-type-color: hsl(170deg 7% 56%); - --cm-bracket-color: #41323f; - --cm-tag-color: #ef6155; - --cm-link-color: #815ba4; - --cm-error-bg-color: #ef6155; - --cm-error-color: #f7f7f7; - --cm-matchingBracket-color: black; - --cm-matchingBracket-bg-color: #1b4bbb21; - --cm-placeholder-text-color: rgba(0, 0, 0, 0.2); - --cm-clickable-underline: #ced2ef; + --cm-color-editor-text: #41323f; + --cm-color-comment: #e96ba8; + --cm-color-atom: #815ba4; + --cm-color-number: #815ba4; + --cm-color-property: #b67a48; + --cm-color-keyword: #ef6155; + --cm-color-string: #da5616; + --cm-color-var: #5668a4; + --cm-color-var2: #37768a; + --cm-color-macro: #5c8c5f; + --cm-color-builtin: #5e7ad3; + --cm-color-function: #cc80ac; + --cm-color-type: hsl(170deg 7% 56%); + --cm-color-bracket: #41323f; + --cm-color-tag: #ef6155; + --cm-color-link: #815ba4; + --cm-color-error-bg: #ef6155; + --cm-color-error: #f7f7f7; + --cm-color-matchingBracket: black; + --cm-color-matchingBracket-bg: #1b4bbb21; + --cm-color-placeholder-text: rgba(0, 0, 0, 0.2); + --cm-color-clickable-underline: #ced2ef; + + /* Mixed parsers */ + --cm-color-html: #48b685; + --cm-color-html-accent: #00ab85; + --cm-color-css: #876800; + --cm-color-css-accent: #696200; + --cm-css-why-doesnt-codemirror-highlight-all-the-text-aaa: #3b3700; + --cm-color-md: #005a9b; + --cm-color-md-accent: #00a9d1; /*autocomplete menu*/ --autocomplete-menu-bg-color: white; @@ -226,14 +237,5 @@ --welcome-recentnotebook-border: #dfdfdf; --welcome-open-bg: #fbfbfb; --welcome-card-author-backdrop: #ffffffb0; - - /* HTML in codemirror! */ - --cm-html-color: #48b685; - --cm-html-accent-color: #00ab85; - --cm-css-color: #876800; - --cm-css-accent-color: #696200; - --cm-css-why-doesnt-codemirror-highlight-all-the-text-aaa: #3b3700; - --cm-md-color: #005a9b; - --cm-md-accent-color: #00a9d1; } } diff --git a/frontend/treeview.css b/frontend/treeview.css index 403f65eb2b..1903494dd5 100644 --- a/frontend/treeview.css +++ b/frontend/treeview.css @@ -2,7 +2,7 @@ @import url("https://cdn.jsdelivr.net/npm/@fontsource/roboto-mono@4.4.5/400-italic.css"); @import url("https://cdn.jsdelivr.net/npm/@fontsource/roboto-mono@4.4.5/700.css"); -@import url("juliamono.css"); +@import url("./fonts/juliamono.css"); /* */ @@ -333,7 +333,7 @@ jlerror li.from_this_notebook .classical-frame { jlerror li a.frame-line-preview { display: block; text-decoration: none; - border: 3px solid var(--cm-clickable-underline); + border: 3px solid var(--cm-color-clickable-underline); --br: 0.6em; border-radius: var(--br); --crop: -0.5em; @@ -368,7 +368,7 @@ jlerror li .frame-line-preview pre > code:not(.frame-line) { } jlerror li .frame-line-preview pre > code::before { content: var(--before-content); - color: var(--cm-line-numbers-color); + color: var(--cm-color-line-numbers); margin-right: 0.7em; width: 2ch; display: inline-block; From b3040258a390c1f9ae4975f6fdbe8d291387baf7 Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Mon, 12 Aug 2024 11:35:10 +0200 Subject: [PATCH 2/4] Don't clear main menu file picker on blur (#2990) --- frontend/components/CellInput.js | 2 +- frontend/components/Editor.js | 2 +- frontend/components/FilePicker.js | 57 +++++++++++------------------ frontend/components/welcome/Open.js | 20 +++++----- 4 files changed, 35 insertions(+), 46 deletions(-) diff --git a/frontend/components/CellInput.js b/frontend/components/CellInput.js index 06e63c9d75..50d4a5c969 100644 --- a/frontend/components/CellInput.js +++ b/frontend/components/CellInput.js @@ -480,7 +480,7 @@ export const CellInput = ({ pluto_actions.move_remote_cells([cell_id], pluto_actions.get_notebook().cell_order.indexOf(cell_id) + (direction === -1 ? -1 : 2)) // workaround for https://github.com/preactjs/preact/issues/4235 - // but the crollintoview behaviour is nice, also when the preact issue is fixed. + // but the scrollIntoView behaviour is nice, also when the preact issue is fixed. requestIdleCallback(() => { cm.dispatch({ // TODO: remove me after fix diff --git a/frontend/components/Editor.js b/frontend/components/Editor.js index b1a705eedd..b33f0e3acd 100644 --- a/frontend/components/Editor.js +++ b/frontend/components/Editor.js @@ -1581,9 +1581,9 @@ The notebook file saves every time you run a cell.` value=${notebook.in_temp_dir ? "" : notebook.path} on_submit=${this.submit_file_change} on_desktop_submit=${this.desktop_submit_file_change} + clear_on_blur=${true} suggest_new_file=${{ base: this.client.session_options?.server?.notebook_path_suggestion ?? "", - name: notebook.shortpath, }} placeholder="Save notebook..." button_label=${notebook.in_temp_dir ? "Choose" : "Move"} diff --git a/frontend/components/FilePicker.js b/frontend/components/FilePicker.js index c44be28d57..77fdab7a17 100644 --- a/frontend/components/FilePicker.js +++ b/frontend/components/FilePicker.js @@ -33,19 +33,12 @@ const assert_not_null = (x) => { } const set_cm_value = (/** @type{EditorView} */ cm, /** @type {string} */ value, scroll = true) => { - let had_focus_before = cm.hasFocus - cm.dispatch({ changes: { from: 0, to: cm.state.doc.length, insert: value }, selection: EditorSelection.cursor(value.length), // a long path like /Users/fons/Documents/article-test-1/asdfasdfasdfsadf.jl does not fit in the little box, so we scroll it to the left so that you can see the filename easily. scrollIntoView: scroll, }) - - if (!had_focus_before) { - // and blur the DOM again (because the previous transaction might have re-focused it) - cm.contentDOM.blur() - } } const is_desktop = !!window.plutoDesktop @@ -63,9 +56,10 @@ if (is_desktop) { * on_submit: (new_path: String) => Promise, * on_desktop_submit?: (loc?: string) => Promise, * client: import("../common/PlutoConnection.js").PlutoConnection, + * clear_on_blur: Boolean, * }} props */ -export const FilePicker = ({ value, suggest_new_file, button_label, placeholder, on_submit, on_desktop_submit, client }) => { +export const FilePicker = ({ value, suggest_new_file, button_label, placeholder, on_submit, on_desktop_submit, client, clear_on_blur }) => { const [is_button_disabled, set_is_button_disabled] = useState(true) const [url_value, set_url_value] = useState("") const forced_value = useRef("") @@ -100,7 +94,9 @@ export const FilePicker = ({ value, suggest_new_file, button_label, placeholder, try { if (is_desktop && on_desktop_submit) { await on_desktop_submit((await guess_notebook_location(url_value)).path_or_url) - } else await on_submit(current_cm.state.doc.toString()) + } else { + await on_submit(current_cm.state.doc.toString()) + } current_cm.dom.blur() } catch (error) { set_cm_value(current_cm, forced_value.current, true) @@ -110,6 +106,19 @@ export const FilePicker = ({ value, suggest_new_file, button_label, placeholder, return true } + const onBlur = (e) => { + const still_in_focus = base.current?.matches(":focus-within") || base.current?.contains(e.relatedTarget) + if (still_in_focus) return + const current_cm = cm.current + if (current_cm == null) return + if (clear_on_blur) + requestAnimationFrame(() => { + if (!current_cm.hasFocus) { + set_cm_value(current_cm, forced_value.current, true) + } + }) + } + const request_path_completions = () => { const current_cm = cm.current if (current_cm == null) return @@ -135,19 +144,12 @@ export const FilePicker = ({ value, suggest_new_file, button_label, placeholder, setTimeout(() => { if (suggest_new_file) { suggest_not_tmp() - } else if (cm.state.doc.length === 0) { + } else { request_path_completions() } }, 0) return true }, - blur: (event, cm) => { - setTimeout(() => { - if (!cm.hasFocus) { - set_cm_value(cm, forced_value.current, true) - } - }, 200) - }, }), EditorView.updateListener.of((update) => { if (update.docChanged) { @@ -217,21 +219,6 @@ export const FilePicker = ({ value, suggest_new_file, button_label, placeholder, mac: "Cmd-Shift-Enter", run: keyMapSubmit, }, - { - key: "Escape", - run: (cm) => { - assert_not_null(close_autocomplete_command).run(cm) - cm.dispatch({ - changes: { from: 0, to: cm.state.doc.length, insert: forced_value.current }, - selection: EditorSelection.cursor(value.length), - effects: EditorView.scrollIntoView(forced_value.current.length), - }) - // @ts-ignore - document.activeElement.blur() - return true - }, - preventDefault: true, - }, { key: "Tab", run: (cm) => { @@ -285,7 +272,7 @@ export const FilePicker = ({ value, suggest_new_file, button_label, placeholder, ` : html` - + ` @@ -293,7 +280,7 @@ export const FilePicker = ({ value, suggest_new_file, button_label, placeholder, const pathhints = ({ client, suggest_new_file }) => - (ctx) => { + (/** @type {autocomplete.CompletionContext} */ ctx) => { const cursor = ctx.state.selection.main.to const oldLine = ctx.state.doc.toString() @@ -302,7 +289,7 @@ const pathhints = query: oldLine, }) .then((update) => { - const queryFileName = oldLine.split("/").pop().split("\\").pop() + const queryFileName = (oldLine.split("/").pop() ?? "").split("\\").pop() ?? "" const results = update.message.results const from = utf8index_to_ut16index(oldLine, update.message.start) diff --git a/frontend/components/welcome/Open.js b/frontend/components/welcome/Open.js index 3a0dc213c1..1c83eef732 100644 --- a/frontend/components/welcome/Open.js +++ b/frontend/components/welcome/Open.js @@ -43,18 +43,20 @@ export const Open = ({ client, connected, CustomPicker, show_samples, on_start_n value="" on_submit=${on_open_path} on_desktop_submit=${desktop_on_open_path} + clear_on_blur=${false} button_label=${window.plutoDesktop ? "Open File" : "Open"} placeholder=${picker.placeholder} /> - ${window.plutoDesktop && - html`<${FilePicker} - key=${picker.placeholder} - client=${client} - value="" - on_desktop_submit=${desktop_on_open_url} - button_label="Open from URL" - placeholder=${picker.placeholder} - />`} + ${window.plutoDesktop != null + ? html`<${FilePicker} + key=${picker.placeholder} + client=${client} + value="" + on_desktop_submit=${desktop_on_open_url} + button_label="Open from URL" + placeholder=${picker.placeholder} + />` + : null} ` } From 61e46558396877d8e7330d0dd317461d4aca1ed9 Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Mon, 12 Aug 2024 15:41:28 +0200 Subject: [PATCH 3/4] variable renames --- frontend/components/Editor.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/frontend/components/Editor.js b/frontend/components/Editor.js index b33f0e3acd..c01acd67c9 100644 --- a/frontend/components/Editor.js +++ b/frontend/components/Editor.js @@ -812,7 +812,7 @@ patch: ${JSON.stringify( } } apply_promise.finally(set_waiting).then(() => { - this.send_queued_bond_changes() + this.maybe_send_queued_bond_changes() }) break @@ -971,18 +971,18 @@ patch: ${JSON.stringify( // Not completely happy with this yet, but it will do for now - DRAL /** Patches that are being delayed until all cells have finished running. */ - this.bonds_changes_to_apply_when_done = [] - this.send_queued_bond_changes = () => { - if (this.notebook_is_idle() && this.bonds_changes_to_apply_when_done.length !== 0) { - // console.log("Applying queued bond changes!", this.bonds_changes_to_apply_when_done) - let bonds_patches = this.bonds_changes_to_apply_when_done - this.bonds_changes_to_apply_when_done = [] + this.bond_changes_to_apply_when_done = [] + this.maybe_send_queued_bond_changes = () => { + if (this.notebook_is_idle() && this.bond_changes_to_apply_when_done.length !== 0) { + // console.log("Applying queued bond changes!", this.bond_changes_to_apply_when_done) + let bonds_patches = this.bond_changes_to_apply_when_done + this.bond_changes_to_apply_when_done = [] this.update_notebook((notebook) => { applyPatches(notebook, bonds_patches) }) } } - /** Whether we just set a bond value which will trigger a cell to run, but we are still waiting for the server to process the bond value (and run the cell). During this time, we won't send new bond values. See https://github.com/fonsp/Pluto.jl/issues/1891 for more info. */ + /** This tracks whether we just set a bond value which will trigger a cell to run, but we are still waiting for the server to process the bond value (and run the cell). During this time, we won't send new bond values. See https://github.com/fonsp/Pluto.jl/issues/1891 for more info. */ this.waiting_for_bond_to_trigger_execution = false /** Number of local updates that have not yet been applied to the server's state. */ this.pending_local_updates = 0 @@ -992,7 +992,7 @@ patch: ${JSON.stringify( */ this.js_init_set = new SetWithEmptyCallback(() => { // console.info("All scripts finished!") - this.send_queued_bond_changes() + this.maybe_send_queued_bond_changes() }) // @ts-ignore This is for tests @@ -1060,7 +1060,7 @@ patch: ${JSON.stringify( let is_idle = this.notebook_is_idle() let changes_involving_bonds = changes.filter((x) => x.path[0] === "bonds") if (!is_idle) { - this.bonds_changes_to_apply_when_done = [...this.bonds_changes_to_apply_when_done, ...changes_involving_bonds] + this.bond_changes_to_apply_when_done = [...this.bond_changes_to_apply_when_done, ...changes_involving_bonds] changes = changes.filter((x) => x.path[0] !== "bonds") } @@ -1430,7 +1430,7 @@ The notebook file saves every time you run a cell.` document.title = "🎈 " + new_state.notebook.shortpath + " β€” Pluto.jl" } - this.send_queued_bond_changes() + this.maybe_send_queued_bond_changes() if (old_state.backend_launch_phase !== this.state.backend_launch_phase && this.state.backend_launch_phase != null) { const phase = Object.entries(BackendLaunchPhase).find(([k, v]) => v == this.state.backend_launch_phase)?.[0] From 01135f7df759c326291c4c86bc4c67210b6d1426 Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Mon, 12 Aug 2024 17:19:09 +0200 Subject: [PATCH 4/4] Fix intermediate bond values again (#2992) --- frontend/components/Editor.js | 4 +- src/evaluation/Run.jl | 3 + test/frontend/__tests__/bonds.js | 66 +++++++++++++- test/frontend/fixtures/test_bind_dynamics.jl | 91 ++++++++++++++++++++ 4 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 test/frontend/fixtures/test_bind_dynamics.jl diff --git a/frontend/components/Editor.js b/frontend/components/Editor.js index c01acd67c9..7070c992fe 100644 --- a/frontend/components/Editor.js +++ b/frontend/components/Editor.js @@ -805,7 +805,9 @@ patch: ${JSON.stringify( const set_waiting = () => { let from_update = message?.response?.update_went_well != null let is_just_acknowledgement = from_update && message.patches.length === 0 - // console.log("Received patches!", message.patches, message.response, is_just_acknowledgement) + let is_relevant_for_bonds = message.patches.some(({ path }) => path.length === 0 || path[0] !== "status_tree") + + // console.debug("Received patches!", is_just_acknowledgement, is_relevant_for_bonds, message.patches, message.response) if (!is_just_acknowledgement) { this.waiting_for_bond_to_trigger_execution = false diff --git a/src/evaluation/Run.jl b/src/evaluation/Run.jl index 81be9f736b..ae1d223578 100644 --- a/src/evaluation/Run.jl +++ b/src/evaluation/Run.jl @@ -57,6 +57,9 @@ function run_reactive_core!( old_workspace_name, _ = WorkspaceManager.bump_workspace_module((session, notebook)) + # A state sync will come soon from this function, so let's delay anything coming from the status_tree listener, see https://github.com/fonsp/Pluto.jl/issues/2978 + Throttled.force_throttle_without_run(notebook.status_tree.update_listener_ref[]) + run_status = Status.report_business_started!(notebook.status_tree, :run) Status.report_business_started!(run_status, :resolve_topology) cell_status = Status.report_business_planned!(run_status, :evaluate) diff --git a/test/frontend/__tests__/bonds.js b/test/frontend/__tests__/bonds.js index af633a3400..0050429d45 100644 --- a/test/frontend/__tests__/bonds.js +++ b/test/frontend/__tests__/bonds.js @@ -1,9 +1,18 @@ import puppeteer from "puppeteer" -import { saveScreenshot, createPage, paste } from "../helpers/common" -import { createNewNotebook, getPlutoUrl, runAllChanged, setupPlutoBrowser, shutdownCurrentNotebook, waitForPlutoToCalmDown } from "../helpers/pluto" +import { saveScreenshot, createPage, paste, waitForContentToBecome, waitForContent } from "../helpers/common" +import { + createNewNotebook, + getPlutoUrl, + importNotebook, + runAllChanged, + setupPlutoBrowser, + shutdownCurrentNotebook, + waitForCellOutput, + waitForPlutoToCalmDown, +} from "../helpers/pluto" // https://github.com/fonsp/Pluto.jl/issues/928 -describe("Bonds should run once when refreshing page", () => { +describe("@bind", () => { /** * Launch a shared browser instance for all tests. * I don't use jest-puppeteer because it takes away a lot of control and works buggy for me, @@ -78,4 +87,55 @@ numberoftimes = Ref(0) }) expect(output_after_reload).toBe(output_after_running_bonds) }) + + it("should ignore intermediate bond values while the notebook is running", async () => { + const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms)) + + const chill = async () => { + await wait(300) + await waitForPlutoToCalmDown(page) + await wait(1500) + await waitForPlutoToCalmDown(page) + } + + await importNotebook(page, "test_bind_dynamics.jl") + await chill() + await chill() + + const id = `029e1d1c-bf42-4e2c-a141-1e2eecc0800d` + const output_selector = `pluto-cell[id="${id}"] pluto-output` + + //page.click is stupid + const click = async (sel) => { + await page.waitForSelector(sel) + await page.evaluate((sel) => document.querySelector(sel).click(), sel) + } + + const reset = async () => { + await click(`#reset_xs_button`) + await wait(300) + await waitForPlutoToCalmDown(page) + await waitForContentToBecome(page, output_selector, "") + await wait(300) + await waitForPlutoToCalmDown(page) + await waitForContentToBecome(page, output_selector, "") + await wait(300) + } + + const start = async () => { + await click(`#add_x_button`) + await chill() + + return await waitForContent(page, output_selector) + } + + await reset() + await start() + + await chill() + + await reset() + const val = await start() + expect(val).toBe("1,done") + }) }) diff --git a/test/frontend/fixtures/test_bind_dynamics.jl b/test/frontend/fixtures/test_bind_dynamics.jl new file mode 100644 index 0000000000..0746d5c805 --- /dev/null +++ b/test/frontend/fixtures/test_bind_dynamics.jl @@ -0,0 +1,91 @@ +### A Pluto.jl notebook ### +# v0.19.45 + +using Markdown +using InteractiveUtils + +# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error). +macro bind(def, element) + quote + local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end + local el = $(esc(element)) + global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el) + el + end +end + +# ╔═║ a0fe4e4d-eee5-4420-bd58-3f12749a9ed1 +@bind reset_xs html"" + +# ╔═║ 58db6bd4-58a6-11ef-3795-fd6e57eceb68 +@bind x html"""
+ + +
""" + +# ╔═║ 8568c646-0233-4a95-8332-2351e9c56027 +@bind withsleep html"" + +# ╔═║ 8a20fa4a-ac02-4a37-a54e-e4224628db66 +x + +# ╔═║ 29f1d840-574e-463c-87d3-4b938e123493 +begin + reset_xs + xs = [] +end + +# ╔═║ 3155b6e0-8e19-4583-b2ab-4ab2db1f10b9 +md""" +Click **reset_xs**. + +Click **Start**. + +The cell below should give: `1,done`. + +Not: `1,2,done` or something like that. That means that an intermediate bond value (`2`) found its way through: [https://github.com/fonsp/Pluto.jl/issues/1891](https://github.com/fonsp/Pluto.jl/issues/1891) +""" + +# ╔═║ 029e1d1c-bf42-4e2c-a141-1e2eecc0800d +begin + withsleep && sleep(1.5) + push!(xs, x) + xs_done = true + + join(xs[2:end], ",") |> Text +end + +# ╔═║ Cell order: +# β•Ÿβ”€a0fe4e4d-eee5-4420-bd58-3f12749a9ed1 +# β•Ÿβ”€58db6bd4-58a6-11ef-3795-fd6e57eceb68 +# β•Ÿβ”€8568c646-0233-4a95-8332-2351e9c56027 +# ╠═8a20fa4a-ac02-4a37-a54e-e4224628db66 +# β•Ÿβ”€3155b6e0-8e19-4583-b2ab-4ab2db1f10b9 +# ╠═029e1d1c-bf42-4e2c-a141-1e2eecc0800d +# ╠═29f1d840-574e-463c-87d3-4b938e123493