diff --git a/NEWS.md b/NEWS.md index ba28b1b34..c2d7b81f8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,6 +2,8 @@ ## Improvements and bug fixes +* `input_code_editor()` now supports `language = "ggsql"` for syntax highlighting of ggsql queries. (#1291) + * Improved the sidebar resize handle to avoid conflicts with the sidebar's native scrollbar and to better support touch devices. (#1299) * `sidebar()` gains a `resizable` argument (default `TRUE`) to control whether the sidebar can be resized by dragging its edge on desktop (wide screen sizes). (#1299) diff --git a/R/sysdata.rda b/R/sysdata.rda index 3f76075dd..1d9ad1727 100644 Binary files a/R/sysdata.rda and b/R/sysdata.rda differ diff --git a/R/versions.R b/R/versions.R index dda38decc..12c707625 100644 --- a/R/versions.R +++ b/R/versions.R @@ -4,4 +4,4 @@ version_bs4 <- "4.6.0" version_bs3 <- "3.4.1" version_accessibility <- "1.0.6" version_prism_code_editor <- "4.2.0" -code_editor_bundled_languages <- c("r", "python", "julia", "sql", "javascript", "typescript", "markup", "css", "scss", "sass", "json", "markdown", "yaml", "xml", "toml", "ini", "bash", "docker", "latex", "cpp", "rust", "diff") +code_editor_bundled_languages <- c("r", "python", "julia", "sql", "ggsql", "javascript", "typescript", "markup", "css", "scss", "sass", "json", "markdown", "yaml", "xml", "toml", "ini", "bash", "docker", "latex", "cpp", "rust", "diff") diff --git a/inst/lib/prism-code-editor/prism/languages/ggsql.js b/inst/lib/prism-code-editor/prism/languages/ggsql.js new file mode 100644 index 000000000..ab1a958c4 --- /dev/null +++ b/inst/lib/prism-code-editor/prism/languages/ggsql.js @@ -0,0 +1,85 @@ +// ggsql.js — ggsql language for prism-code-editor +// +// AUTO-GENERATED by tools/build_ggsql_grammar.R from the TextMate grammar at: +// https://github.com/posit-dev/ggsql/blob/main/ggsql-vscode/syntaxes/ggsql.tmLanguage.json +// Do not edit by hand. +// +// NOTE: The import path below is a content-hashed internal module of +// prism-code-editor. If bslib updates prism-code-editor, this hash may change. +// Re-run this script to regenerate. + +import "./sql.js"; +import { l as languages } from "../../index-C1_GGQ8y.js"; + +var sql = languages.sql; +var ggsql = {}; + +// Copy SQL tokens +Object.keys(sql).forEach(function(k) { ggsql[k] = sql[k]; }); + +// ggsql clause keywords +ggsql["ggsql-keyword"] = { + pattern: /\b(?:VISUALISE|VISUALIZE|DRAW|PLACE|SCALE|FACET|PROJECT|LABEL|MAPPING|REMAPPING|SETTING|FILTER|FROM|ORDER|BY|PARTITION|RENAMING|AS|TO|VIA)\b/i, + alias: "keyword", +}; + +// Geom types +ggsql["ggsql-geom"] = { + pattern: /\b(?:point|line|path|bar|col|area|tile|polygon|ribbon|histogram|density|smooth|boxplot|violin|text|label|segment|arrow|rule|errorbar|rect)\b/, + alias: "builtin", +}; + +// Scale type modifiers +ggsql["ggsql-scale-type"] = { + pattern: /\b(?:CONTINUOUS|DISCRETE|BINNED|ORDINAL|IDENTITY)\b/i, + alias: "builtin", +}; + +// Scale type values +ggsql["ggsql-scale-value"] = { + pattern: /\b(?:linear|log|log10|log2|sqrt|reverse|date|datetime|time|viridis|plasma|magma|inferno|cividis|diverging|sequential|identity)\b/, + alias: "string", +}; + +// Aesthetic names +ggsql["ggsql-aesthetic"] = { + pattern: /\b(?:x|y|xmin|xmax|ymin|ymax|xend|yend|theta|radius|thetamin|thetamax|radiusmin|radiusmax|thetaend|radiusend|color|colour|fill|stroke|opacity|size|shape|linetype|linewidth|width|height|label|family|fontface|hjust|vjust|weight|coef|intercept|offset|density|count|intensity|panel|row|column)\b/, + alias: "attr-name", +}; + +// Property names +ggsql["ggsql-property"] = { + pattern: /\b(?:type|limits|breaks|labels|expand|direction|na_value|palette|domain|range|free|ncol|missing|xlim|ylim|ratio|angle|clip|start|title|subtitle|x|y|caption|tag|color|colour|fill|size|shape|linetype)\b/, + alias: "property", +}; + +// Project types +ggsql["ggsql-project"] = { + pattern: /\b(?:cartesian|polar)\b/, + alias: "class-name", +}; + +// Fat arrow operator +ggsql["ggsql-arrow"] = { + pattern: /=>/, + alias: "operator", +}; + +// SQL functions (aggregate, window, datetime, string, math, conversion, conditional, JSON, list) +ggsql["function"] = /\b(?:count|sum|avg|min|max|stddev|variance|array_agg|string_agg|group_concat|row_number|rank|dense_rank|ntile|lag|lead|first_value|last_value|nth_value|cume_dist|percent_rank|date_trunc|date_part|datepart|datename|dateadd|datediff|extract|now|current_date|current_time|current_timestamp|getdate|getutcdate|strftime|strptime|make_date|make_time|make_timestamp|concat|substring|substr|left|right|length|len|char_length|lower|upper|trim|ltrim|rtrim|replace|reverse|repeat|lpad|rpad|split_part|string_split|format|printf|regexp_replace|regexp_extract|regexp_matches|abs|ceil|ceiling|floor|round|trunc|truncate|mod|power|sqrt|exp|ln|log|log10|log2|sign|sin|cos|tan|asin|acos|atan|atan2|pi|degrees|radians|random|rand|cast|convert|coalesce|nullif|ifnull|isnull|nvl|try_cast|typeof|if|iff|iif|greatest|least|decode|json|json_extract|json_extract_path|json_extract_string|json_value|json_query|json_object|json_array|json_array_length|to_json|from_json|list|list_value|list_aggregate|array_length|unnest|generate_series|range)(?=\s*\()/i; + +// Reorder: ggsql tokens before generic SQL keyword/boolean +var ordered = {}; +["comment", "variable", "string", "identifier"].forEach(function(k) { + if (k in ggsql) ordered[k] = ggsql[k]; +}); +["ggsql-keyword", "ggsql-geom", "ggsql-scale-type", "ggsql-scale-value", + "ggsql-aesthetic", "ggsql-property", "ggsql-project", "ggsql-arrow"].forEach(function(k) { + if (k in ggsql) ordered[k] = ggsql[k]; +}); +Object.keys(ggsql).forEach(function(k) { + if (!(k in ordered)) ordered[k] = ggsql[k]; +}); + +languages.ggsql = ordered; + diff --git a/man/figures/navset-card-pill.png b/man/figures/navset-card-pill.png index 3339a1b21..f1c542fee 100644 Binary files a/man/figures/navset-card-pill.png and b/man/figures/navset-card-pill.png differ diff --git a/man/figures/navset-card-underline.png b/man/figures/navset-card-underline.png index ae7c70618..df9d58dd0 100644 Binary files a/man/figures/navset-card-underline.png and b/man/figures/navset-card-underline.png differ diff --git a/man/figures/navset-pill-list.png b/man/figures/navset-pill-list.png index 3d98a9be0..e1a03867c 100644 Binary files a/man/figures/navset-pill-list.png and b/man/figures/navset-pill-list.png differ diff --git a/man/figures/navset-pill.png b/man/figures/navset-pill.png index 006f05e9a..3d13e979b 100644 Binary files a/man/figures/navset-pill.png and b/man/figures/navset-pill.png differ diff --git a/man/figures/navset-tab-basic.png b/man/figures/navset-tab-basic.png index c67eecbb0..25105ec4e 100644 Binary files a/man/figures/navset-tab-basic.png and b/man/figures/navset-tab-basic.png differ diff --git a/man/figures/navset-tab-card.png b/man/figures/navset-tab-card.png index a188a3b64..1915a66cb 100644 Binary files a/man/figures/navset-tab-card.png and b/man/figures/navset-tab-card.png differ diff --git a/man/figures/navset-tab.png b/man/figures/navset-tab.png index 8ea82bf92..068f0bbe5 100644 Binary files a/man/figures/navset-tab.png and b/man/figures/navset-tab.png differ diff --git a/man/figures/navset-underline.png b/man/figures/navset-underline.png index f53b75739..f1e060347 100644 Binary files a/man/figures/navset-underline.png and b/man/figures/navset-underline.png differ diff --git a/man/figures/page-navbar.png b/man/figures/page-navbar.png index 65b6bc1b5..46dba1561 100644 Binary files a/man/figures/page-navbar.png and b/man/figures/page-navbar.png differ diff --git a/man/figures/value-box-background-color.png b/man/figures/value-box-background-color.png index fa2cb242a..0fc2436fa 100644 Binary files a/man/figures/value-box-background-color.png and b/man/figures/value-box-background-color.png differ diff --git a/man/figures/value-box-background-theme.png b/man/figures/value-box-background-theme.png index eda14e2f6..d86fba364 100644 Binary files a/man/figures/value-box-background-theme.png and b/man/figures/value-box-background-theme.png differ diff --git a/man/figures/value-box-custom.png b/man/figures/value-box-custom.png index 459f96be7..d256795f0 100644 Binary files a/man/figures/value-box-custom.png and b/man/figures/value-box-custom.png differ diff --git a/man/figures/value-box-gradient-1.png b/man/figures/value-box-gradient-1.png index 370cd3882..219155f12 100644 Binary files a/man/figures/value-box-gradient-1.png and b/man/figures/value-box-gradient-1.png differ diff --git a/man/figures/value-box-named-color.png b/man/figures/value-box-named-color.png index 361778e31..b1b94e9f3 100644 Binary files a/man/figures/value-box-named-color.png and b/man/figures/value-box-named-color.png differ diff --git a/man/figures/value-box-named-theme.png b/man/figures/value-box-named-theme.png index 8770602a6..08cad55b3 100644 Binary files a/man/figures/value-box-named-theme.png and b/man/figures/value-box-named-theme.png differ diff --git a/man/figures/value-box-showcase-bottom.png b/man/figures/value-box-showcase-bottom.png index ee0c8c04d..05e533f6a 100644 Binary files a/man/figures/value-box-showcase-bottom.png and b/man/figures/value-box-showcase-bottom.png differ diff --git a/man/figures/value-box-showcase-left-center.png b/man/figures/value-box-showcase-left-center.png index 965fba0b7..8a98546f7 100644 Binary files a/man/figures/value-box-showcase-left-center.png and b/man/figures/value-box-showcase-left-center.png differ diff --git a/man/figures/value-box-showcase-top-right.png b/man/figures/value-box-showcase-top-right.png index db9bdacb9..dc4e006db 100644 Binary files a/man/figures/value-box-showcase-top-right.png and b/man/figures/value-box-showcase-top-right.png differ diff --git a/man/figures/value-box-text-color.png b/man/figures/value-box-text-color.png index 426724a91..787533537 100644 Binary files a/man/figures/value-box-text-color.png and b/man/figures/value-box-text-color.png differ diff --git a/man/figures/value-box-text-theme.png b/man/figures/value-box-text-theme.png index 1f4068f95..fda1b1644 100644 Binary files a/man/figures/value-box-text-theme.png and b/man/figures/value-box-text-theme.png differ diff --git a/man/figures/value-box-theme-class.png b/man/figures/value-box-theme-class.png index 4cf321455..a5a850f9d 100644 Binary files a/man/figures/value-box-theme-class.png and b/man/figures/value-box-theme-class.png differ diff --git a/tests/testthat/_snaps/input-code-editor.md b/tests/testthat/_snaps/input-code-editor.md index 7ff48315f..680ce96dc 100644 --- a/tests/testthat/_snaps/input-code-editor.md +++ b/tests/testthat/_snaps/input-code-editor.md @@ -12,7 +12,7 @@ input_code_editor("test", language = "fortran") Condition Error in `input_code_editor()`: - ! `language` must be one of "r", "python", "julia", "sql", "javascript", "typescript", "markup", "css", "scss", "sass", "json", "markdown", "yaml", "xml", "toml", "ini", "bash", "docker", "latex", "cpp", "rust", "diff", "md", "html", "plain", "plaintext", "text", or "txt", not "fortran". + ! `language` must be one of "r", "python", "julia", "sql", "ggsql", "javascript", "typescript", "markup", "css", "scss", "sass", "json", "markdown", "yaml", "xml", "toml", "ini", "bash", "docker", "latex", "cpp", "rust", "diff", "md", "html", "plain", "plaintext", "text", or "txt", not "fortran". # input_code_editor validates theme names @@ -33,7 +33,7 @@ input_code_editor("test", language = "fortran") Condition Error in `input_code_editor()`: - ! `language` must be one of "r", "python", "julia", "sql", "javascript", "typescript", "markup", "css", "scss", "sass", "json", "markdown", "yaml", "xml", "toml", "ini", "bash", "docker", "latex", "cpp", "rust", "diff", "md", "html", "plain", "plaintext", "text", or "txt", not "fortran". + ! `language` must be one of "r", "python", "julia", "sql", "ggsql", "javascript", "typescript", "markup", "css", "scss", "sass", "json", "markdown", "yaml", "xml", "toml", "ini", "bash", "docker", "latex", "cpp", "rust", "diff", "md", "html", "plain", "plaintext", "text", or "txt", not "fortran". # update_code_editor validates inputs @@ -41,7 +41,7 @@ update_code_editor("test", language = "fortran", session = NULL) Condition Error in `update_code_editor()`: - ! `language` must be one of "r", "python", "julia", "sql", "javascript", "typescript", "markup", "css", "scss", "sass", "json", "markdown", "yaml", "xml", "toml", "ini", "bash", "docker", "latex", "cpp", "rust", "diff", "md", "html", "plain", "plaintext", "text", or "txt", not "fortran". + ! `language` must be one of "r", "python", "julia", "sql", "ggsql", "javascript", "typescript", "markup", "css", "scss", "sass", "json", "markdown", "yaml", "xml", "toml", "ini", "bash", "docker", "latex", "cpp", "rust", "diff", "md", "html", "plain", "plaintext", "text", or "txt", not "fortran". --- diff --git a/tools/build_ggsql_grammar.R b/tools/build_ggsql_grammar.R new file mode 100644 index 000000000..461fa3622 --- /dev/null +++ b/tools/build_ggsql_grammar.R @@ -0,0 +1,315 @@ +#!/usr/bin/env Rscript +# +# Build the ggsql Prism grammar file from the TextMate grammar source. +# +# Usage: +# Rscript tools/build_ggsql_grammar.R +# +# This fetches the ggsql TextMate grammar from posit-dev/ggsql on GitHub, +# extracts token patterns, and generates a Prism-compatible grammar file +# that extends the built-in SQL grammar. +# +# The output is written to: +# inst/lib/prism-code-editor/prism/languages/ggsql.js + +TMGRAMMAR_URL <- "https://raw.githubusercontent.com/posit-dev/ggsql/main/ggsql-vscode/syntaxes/ggsql.tmLanguage.json" + +# Paths relative to the bslib package root +LANGUAGES_DIR <- "inst/lib/prism-code-editor/prism/languages" +SQL_JS <- file.path(LANGUAGES_DIR, "sql.js") +OUTPUT_JS <- file.path(LANGUAGES_DIR, "ggsql.js") + +# ---- Helpers ---- + +# Extract word alternatives from a TextMate match pattern like +# "\\b(word1|word2|word3)\\b" or "\\b(?i:word1|word2)\\b" +extract_words <- function(match_pattern) { + # Try non-capture group with flags first: \b(?i:word1|word2)\b + m <- regmatches( + match_pattern, + regexec("\\\\b\\(\\?[a-z]*:([^)]+)\\)\\\\b", match_pattern) + )[[1]] + if (length(m) == 2) { + return(strsplit(m[2], "\\|")[[1]]) + } + + # Try capture group: \b(word1|word2)\b + m <- regmatches( + match_pattern, + regexec("\\\\b\\(([^)]+)\\)\\\\b", match_pattern) + )[[1]] + if (length(m) == 2) { + return(strsplit(m[2], "\\|")[[1]]) + } + + NULL +} + +# Extract word alternatives from a function pattern like +# "(?i)\\b(func1|func2)\\b\\s*\\(" +extract_function_words <- function(match_pattern) { + m <- regmatches( + match_pattern, + regexec("\\\\b\\(([^)]+)\\)\\\\b\\\\s\\*\\\\\\(", match_pattern) + )[[1]] + if (length(m) == 2) { + return(strsplit(m[2], "\\|")[[1]]) + } + NULL +} + +# Format a word list as a JS regex alternation: /\b(?:word1|word2)\b/flags +format_word_regex <- function(words, flags = "") { + alts <- paste(words, collapse = "|") + sprintf("/\\b(?:%s)\\b/%s", alts, flags) +} + +# Format function words with lookahead: /\b(?:func1|func2)(?=\s*\()/flags +format_function_regex <- function(words, flags = "i") { + alts <- paste(words, collapse = "|") + sprintf("/\\b(?:%s)(?=\\s*\\()/%s", alts, flags) +} + +# Extract the content-hashed import path from sql.js +extract_import_path <- function(sql_js_path) { + lines <- readLines(sql_js_path, n = 1) + m <- regmatches(lines, regexec('"([^"]+index-[^"]+\\.js)"', lines))[[1]] + if (length(m) < 2) { + stop("Could not extract import path from ", sql_js_path) + } + m[2] +} + +# ---- Main ---- + +main <- function() { + if (!file.exists(SQL_JS)) { + stop("sql.js not found at ", SQL_JS, ". Run from the bslib package root.") + } + + message("Fetching TextMate grammar from: ", TMGRAMMAR_URL) + grammar <- jsonlite::fromJSON(TMGRAMMAR_URL, simplifyDataFrame = FALSE) + repo <- grammar$repository + + import_path <- extract_import_path(SQL_JS) + message("Using import path: ", import_path) + + # -- Extract ggsql clause keywords -- + # Collect from: begin captures of clause patterns + keyword.other matches + clause_keywords <- character(0) + + # Clause names come from the `begin` regex of each *-clause pattern + clause_names <- grep("-clause$", names(repo), value = TRUE) + for (clause_name in clause_names) { + clause <- repo[[clause_name]] + if (!is.null(clause$begin)) { + words <- extract_words(clause$begin) + if (!is.null(words)) clause_keywords <- c(clause_keywords, words) + } + } + + # Also collect keyword.other.ggsql from all clause patterns and common-clause-patterns + keyword_sources <- c("common-clause-patterns", clause_names) + for (src in keyword_sources) { + for (p in repo[[src]]$patterns) { + if (identical(p$name, "keyword.other.ggsql")) { + words <- extract_words(p$match) + if (!is.null(words)) clause_keywords <- c(clause_keywords, words) + } + } + } + clause_keywords <- unique(clause_keywords) + + # -- Extract token groups from named patterns -- + # Searches all patterns in repo_key(s) for token_name, accumulating words + # across multiple matching patterns. + extract_token_group <- function(repo_keys, token_name) { + words <- character(0) + for (repo_key in repo_keys) { + if (is.null(repo[[repo_key]])) { + stop( + "Repository key '", + repo_key, + "' not found in TextMate grammar. ", + "The upstream grammar structure may have changed." + ) + } + for (p in repo[[repo_key]]$patterns) { + if (identical(p$name, token_name)) { + w <- extract_words(p$match) + if (!is.null(w)) words <- c(words, w) + } + } + } + if (length(words) == 0) { + stop( + "No words extracted for '", + token_name, + "' from ", + paste(repo_keys, collapse = ", "), + ". ", + "The upstream grammar structure may have changed." + ) + } + unique(words) + } + + geoms <- extract_token_group( + c("draw-clause", "place-clause"), + "support.type.geom.ggsql" + ) + scale_types <- extract_token_group( + "scale-clause", + "keyword.control.scale-modifier.ggsql" + ) + scale_values <- extract_token_group( + "scale-clause", + "constant.language.scale-type.ggsql" + ) + aesthetics <- extract_token_group( + "aesthetics", + "support.type.aesthetic.ggsql" + ) + properties <- extract_token_group( + c("scale-clause", "facet-clause", "project-clause", "label-clause"), + "support.type.property.ggsql" + ) + projects <- extract_token_group( + "project-clause", + "support.type.project.ggsql" + ) + + # -- Extract SQL function names -- + all_functions <- character(0) + for (p in repo[["sql-functions"]]$patterns) { + words <- extract_function_words(p$match) + if (!is.null(words)) all_functions <- c(all_functions, words) + } + all_functions <- unique(all_functions) + + if (length(clause_keywords) == 0) { + stop( + "No clause keywords extracted. The upstream grammar structure may have changed." + ) + } + if (length(all_functions) == 0) { + stop( + "No SQL functions extracted. The upstream grammar structure may have changed." + ) + } + + # -- Generate the JS file -- + js <- c( + "// ggsql.js — ggsql language for prism-code-editor", + "//", + "// AUTO-GENERATED by tools/build_ggsql_grammar.R from the TextMate grammar at:", + "// https://github.com/posit-dev/ggsql/blob/main/ggsql-vscode/syntaxes/ggsql.tmLanguage.json", + "// Do not edit by hand.", + "//", + "// NOTE: The import path below is a content-hashed internal module of", + "// prism-code-editor. If bslib updates prism-code-editor, this hash may change.", + "// Re-run this script to regenerate.", + "", + 'import "./sql.js";', + sprintf('import { l as languages } from "%s";', import_path), + "", + "var sql = languages.sql;", + "var ggsql = {};", + "", + "// Copy SQL tokens", + 'Object.keys(sql).forEach(function(k) { ggsql[k] = sql[k]; });', + "", + sprintf( + r"(// ggsql clause keywords +ggsql["ggsql-keyword"] = { + pattern: %s, + alias: "keyword", +};)", + format_word_regex(clause_keywords, flags = "i") + ), + "", + sprintf( + r"(// Geom types +ggsql["ggsql-geom"] = { + pattern: %s, + alias: "builtin", +};)", + format_word_regex(geoms) + ), + "", + sprintf( + r"(// Scale type modifiers +ggsql["ggsql-scale-type"] = { + pattern: %s, + alias: "builtin", +};)", + format_word_regex(scale_types, flags = "i") + ), + "", + sprintf( + r"(// Scale type values +ggsql["ggsql-scale-value"] = { + pattern: %s, + alias: "string", +};)", + format_word_regex(scale_values) + ), + "", + sprintf( + r"(// Aesthetic names +ggsql["ggsql-aesthetic"] = { + pattern: %s, + alias: "attr-name", +};)", + format_word_regex(aesthetics) + ), + "", + sprintf( + r"(// Property names +ggsql["ggsql-property"] = { + pattern: %s, + alias: "property", +};)", + format_word_regex(properties) + ), + "", + sprintf( + r"(// Project types +ggsql["ggsql-project"] = { + pattern: %s, + alias: "class-name", +};)", + format_word_regex(projects) + ), + "", + "// Fat arrow operator", + 'ggsql["ggsql-arrow"] = {', + " pattern: /=>/,", + ' alias: "operator",', + "};", + "", + "// SQL functions (aggregate, window, datetime, string, math, conversion, conditional, JSON, list)", + sprintf('ggsql["function"] = %s;', format_function_regex(all_functions)), + "", + "// Reorder: ggsql tokens before generic SQL keyword/boolean", + "var ordered = {};", + '["comment", "variable", "string", "identifier"].forEach(function(k) {', + " if (k in ggsql) ordered[k] = ggsql[k];", + "});", + '["ggsql-keyword", "ggsql-geom", "ggsql-scale-type", "ggsql-scale-value",', + ' "ggsql-aesthetic", "ggsql-property", "ggsql-project", "ggsql-arrow"].forEach(function(k) {', + " if (k in ggsql) ordered[k] = ggsql[k];", + "});", + "Object.keys(ggsql).forEach(function(k) {", + " if (!(k in ordered)) ordered[k] = ggsql[k];", + "});", + "", + "languages.ggsql = ordered;", + "" + ) + + writeLines(js, OUTPUT_JS) + message("Generated: ", OUTPUT_JS) +} + +main() diff --git a/tools/main.R b/tools/main.R index ed685ff1f..d158e4c77 100644 --- a/tools/main.R +++ b/tools/main.R @@ -10,7 +10,8 @@ lapply( "download_preset_fonts.R", "update_gfont_info.R", "expand_variables_article_template.R", - "compile_component_sass.R" + "compile_component_sass.R", + "build_ggsql_grammar.R" ), function(file) { message("Updating: ", file) diff --git a/tools/yarn_install.R b/tools/yarn_install.R index da6c8226d..c4fe55a9b 100755 --- a/tools/yarn_install.R +++ b/tools/yarn_install.R @@ -340,6 +340,7 @@ with_dir("inst/lib", { "python", "julia", "sql", + "ggsql", # Web/Frontend "javascript", "typescript", @@ -402,9 +403,16 @@ with_dir("inst/lib", { file.path(dest, "languages") ) - # Copy prism grammars (only bundled) + # Copy prism grammars (only bundled, filtered to those that exist upstream) + bundled_prism_files <- file.path( + src, + "prism", + "languages", + bundled_lang_files + ) + bundled_prism_files <- bundled_prism_files[file.exists(bundled_prism_files)] file.copy( - file.path(src, "prism", "languages", bundled_lang_files), + bundled_prism_files, file.path(dest, "prism", "languages") ) @@ -547,6 +555,9 @@ with_dir("inst/lib", { unlink("prism-code-editor-full", recursive = TRUE) cat("\n\n==== Finished prism-code-editor ====\n") + cat( + "NOTE: Run `Rscript tools/build_ggsql_grammar.R` to regenerate ggsql.js\n" + ) # GitHub reports security issues of devDependencies, but that's irrelevant to us remove_dev_dependencies <- function(pkg_file) {