From d2426d2867d27a5a312f658ac8b6e5af49448d7d Mon Sep 17 00:00:00 2001 From: Carson Date: Fri, 6 Mar 2026 19:22:06 -0600 Subject: [PATCH 1/3] feat: add ggsql as a bundled language for input_code_editor Add ggsql language support to prism-code-editor. The grammar file extends SQL with ggsql-specific tokens for visualization queries. Depends on rstudio/bslib#feat/ggsql-language for the grammar source. Co-Authored-By: Claude Opus 4.6 --- shiny/ui/_input_code_editor_bundle.py | 1 + .../prism/languages/ggsql.js | 78 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 shiny/www/shared/prism-code-editor/prism/languages/ggsql.js diff --git a/shiny/ui/_input_code_editor_bundle.py b/shiny/ui/_input_code_editor_bundle.py index 61c726cf4..3d085f494 100644 --- a/shiny/ui/_input_code_editor_bundle.py +++ b/shiny/ui/_input_code_editor_bundle.py @@ -12,6 +12,7 @@ "css", "diff", "docker", + "ggsql", "ini", "javascript", "json", diff --git a/shiny/www/shared/prism-code-editor/prism/languages/ggsql.js b/shiny/www/shared/prism-code-editor/prism/languages/ggsql.js new file mode 100644 index 000000000..da733fe12 --- /dev/null +++ b/shiny/www/shared/prism-code-editor/prism/languages/ggsql.js @@ -0,0 +1,78 @@ +// ggsql.js — ggsql language for prism-code-editor +// +// Extends the SQL grammar with ggsql-specific tokens. +// Derived from the TextMate grammar at: +// https://github.com/posit-dev/ggsql/blob/main/ggsql-vscode/syntaxes/ggsql.tmLanguage.json +// +// NOTE: The import path (index-XXXXXXX.js) is a content-hashed internal module. +// If bslib updates prism-code-editor, this hash may change. Check sql.js for +// the current filename. + +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|MAPPING|REMAPPING|SETTING|FILTER|PARTITION|SCALE|FACET|PROJECT|LABEL|THEME|RENAMING|VIA|TO)\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|hline|vline|abline|errorbar)\b/, + alias: "builtin", +}; + +// Scale type modifiers +ggsql["ggsql-scale-type"] = { + pattern: /\b(?:CONTINUOUS|DISCRETE|BINNED|ORDINAL|IDENTITY)\b/i, + alias: "builtin", +}; + +// Aesthetic names +ggsql["ggsql-aesthetic"] = { + pattern: /\b(?:x|y|xmin|xmax|ymin|ymax|xend|yend|weight|color|colour|fill|stroke|opacity|size|shape|linetype|linewidth|width|height|family|fontface|hjust|vjust|panel|row|column|theta|radius|thetamin|thetamax|radiusmin|radiusmax|thetaend|radiusend|offset)\b/, + alias: "attr-name", +}; + +// Theme names +ggsql["ggsql-theme"] = { + pattern: /\b(?:minimal|classic|gray|grey|bw|dark|light|void)\b/, + alias: "class-name", +}; + +// Project types +ggsql["ggsql-project"] = { + pattern: /\b(?:cartesian|polar|flip|fixed|trans|map|quickmap)\b/, + alias: "class-name", +}; + +// Fat arrow operator +ggsql["ggsql-arrow"] = { + pattern: /=>/, + alias: "operator", +}; + +// Broader SQL function 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|first|last)(?=\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-aesthetic", + "ggsql-theme", "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; From a8ff7303d34df3a00a69e72384901a9b7a1b7220 Mon Sep 17 00:00:00 2001 From: Carson Date: Fri, 6 Mar 2026 19:28:47 -0600 Subject: [PATCH 2/3] chore: update ggsql.js from bslib build script output Regenerated by Rscript tools/build_ggsql_grammar.R in bslib. Co-Authored-By: Claude Opus 4.6 --- .../prism/languages/ggsql.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/shiny/www/shared/prism-code-editor/prism/languages/ggsql.js b/shiny/www/shared/prism-code-editor/prism/languages/ggsql.js index da733fe12..ed2c1801d 100644 --- a/shiny/www/shared/prism-code-editor/prism/languages/ggsql.js +++ b/shiny/www/shared/prism-code-editor/prism/languages/ggsql.js @@ -1,12 +1,12 @@ // ggsql.js — ggsql language for prism-code-editor // -// Extends the SQL grammar with ggsql-specific tokens. -// Derived from the TextMate grammar at: +// 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 (index-XXXXXXX.js) is a content-hashed internal module. -// If bslib updates prism-code-editor, this hash may change. Check sql.js for -// the current filename. +// 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"; @@ -19,7 +19,7 @@ Object.keys(sql).forEach(function(k) { ggsql[k] = sql[k]; }); // ggsql clause keywords ggsql["ggsql-keyword"] = { - pattern: /\b(?:VISUALISE|VISUALIZE|DRAW|MAPPING|REMAPPING|SETTING|FILTER|PARTITION|SCALE|FACET|PROJECT|LABEL|THEME|RENAMING|VIA|TO)\b/i, + pattern: /\b(?:VISUALISE|VISUALIZE|DRAW|SCALE|FACET|PROJECT|LABEL|THEME|MAPPING|REMAPPING|SETTING|FILTER|FROM|ORDER|BY|PARTITION|RENAMING|TO|VIA)\b/i, alias: "keyword", }; @@ -37,7 +37,7 @@ ggsql["ggsql-scale-type"] = { // Aesthetic names ggsql["ggsql-aesthetic"] = { - pattern: /\b(?:x|y|xmin|xmax|ymin|ymax|xend|yend|weight|color|colour|fill|stroke|opacity|size|shape|linetype|linewidth|width|height|family|fontface|hjust|vjust|panel|row|column|theta|radius|thetamin|thetamax|radiusmin|radiusmax|thetaend|radiusend|offset)\b/, + pattern: /\b(?:x|y|xmin|xmax|ymin|ymax|xend|yend|weight|color|colour|fill|stroke|opacity|size|shape|linetype|linewidth|width|height|label|family|fontface|hjust|vjust|panel|row|column)\b/, alias: "attr-name", }; @@ -59,8 +59,8 @@ ggsql["ggsql-arrow"] = { alias: "operator", }; -// Broader SQL function 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|first|last)(?=\s*\()/i; +// 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 = {}; @@ -76,3 +76,4 @@ Object.keys(ggsql).forEach(function(k) { }); languages.ggsql = ordered; + From 60d907a09983cf0d6e51fabeddf125d82ae99876 Mon Sep 17 00:00:00 2001 From: Carson Date: Fri, 6 Mar 2026 19:33:24 -0600 Subject: [PATCH 3/3] chore: update ggsql.js from bslib build script output Co-Authored-By: Claude Opus 4.6 --- shiny/www/shared/prism-code-editor/prism/languages/ggsql.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shiny/www/shared/prism-code-editor/prism/languages/ggsql.js b/shiny/www/shared/prism-code-editor/prism/languages/ggsql.js index ed2c1801d..7f2574cd4 100644 --- a/shiny/www/shared/prism-code-editor/prism/languages/ggsql.js +++ b/shiny/www/shared/prism-code-editor/prism/languages/ggsql.js @@ -19,7 +19,7 @@ Object.keys(sql).forEach(function(k) { ggsql[k] = sql[k]; }); // ggsql clause keywords ggsql["ggsql-keyword"] = { - pattern: /\b(?:VISUALISE|VISUALIZE|DRAW|SCALE|FACET|PROJECT|LABEL|THEME|MAPPING|REMAPPING|SETTING|FILTER|FROM|ORDER|BY|PARTITION|RENAMING|TO|VIA)\b/i, + pattern: /\b(?:VISUALISE|VISUALIZE|DRAW|SCALE|FACET|PROJECT|LABEL|THEME|MAPPING|REMAPPING|SETTING|FILTER|FROM|ORDER|BY|PARTITION|RENAMING|AS|TO|VIA)\b/i, alias: "keyword", };