Discourse Stan highlighting

This is for whomever maintains the discourse server. I know @jonah has helped in the past.

Discourse uses highlight.js and Stan highlighting updates were recently merged. Highlight.js has not made a new release but once it does we can ping Discourse to pull in the recent update.

If we want, we can test a manual update (not sure it will work unless we build the entire thing, though that’s pretty easy as well) to the Discourse code at https://github.com/discourse/discourse/blob/main/vendor/assets/javascripts/highlightjs/language/stan.min.js and replacing with the updated stan.min.js which I compiled on my computer:

stan.min.js file


/*! `stan` grammar compiled for Highlight.js 11.3.1 */
var hljsGrammar=(()=>{"use strict";return e=>{
const _=e.regex,o=["bernoulli","bernoulli_logit","bernoulli_logit_glm","beta","beta_binomial","beta_proportion","binomial","binomial_logit","categorical","categorical_logit","categorical_logit_glm","cauchy","chi_square","dirichlet","discrete_range","double_exponential","exp_mod_normal","exponential","frechet","gamma","gaussian_dlm_obs","gumbel","hmm_latent","hypergeometric","inv_chi_square","inv_gamma","inv_wishart","lkj_corr","lkj_corr_cholesky","logistic","lognormal","multi_gp","multi_gp_cholesky","multi_normal","multi_normal_cholesky","multi_normal_prec","multi_student_t","multinomial","multinomial_logit","neg_binomial","neg_binomial_2","neg_binomial_2_log","neg_binomial_2_log_glm","normal","normal_id_glm","ordered_logistic","ordered_logistic_glm","ordered_probit","pareto","pareto_type_2","poisson","poisson_log","poisson_log_glm","rayleigh","scaled_inv_chi_square","skew_double_exponential","skew_normal","std_normal","student_t","uniform","von_mises","weibull","wiener","wishart"],r=e.COMMENT(/\/\*/,/\*\//,{
relevance:0,contains:[{scope:"doctag",match:/@(return|param)/}]}),i={
scope:"meta",begin:/#include\b/,end:/$/,contains:[{match:/[a-z][a-z-._]+/,
scope:"string"},e.C_LINE_COMMENT_MODE]
},t=["lower","upper","offset","multiplier"];return{name:"Stan",
aliases:["stanfuncs"],keywords:{$pattern:e.IDENT_RE,
title:["functions","model","data","parameters","quantities","transformed","generated"],
type:["array","complex","int","real","vector","ordered","positive_ordered","simplex","unit_vector","row_vector","matrix","cholesky_factor_corr|10","cholesky_factor_cov|10","corr_matrix|10","cov_matrix|10","void"],
keyword:["for","in","if","else","while","break","continue","return"],
built_in:["Phi","Phi_approx","abs","acos","acosh","add_diag","algebra_solver","algebra_solver_newton","append_array","append_col","append_row","asin","asinh","atan","atan2","atanh","bessel_first_kind","bessel_second_kind","binary_log_loss","binomial_coefficient_log","block","cbrt","ceil","chol2inv","cholesky_decompose","choose","col","cols","columns_dot_product","columns_dot_self","conj","cos","cosh","cov_exp_quad","crossprod","csr_extract_u","csr_extract_v","csr_extract_w","csr_matrix_times_vector","csr_to_dense_matrix","cumulative_sum","determinant","diag_matrix","diag_post_multiply","diag_pre_multiply","diagonal","digamma","dims","distance","dot_product","dot_self","eigenvalues_sym","eigenvectors_sym","erf","erfc","exp","exp2","expm1","fabs","falling_factorial","fdim","floor","fma","fmax","fmin","fmod","gamma_p","gamma_q","generalized_inverse","get_imag","get_lp","get_real","head","hmm_hidden_state_prob","hmm_marginal","hypot","identity_matrix","inc_beta","int_step","integrate_1d","integrate_ode","integrate_ode_adams","integrate_ode_bdf","integrate_ode_rk45","inv","inv_Phi","inv_cloglog","inv_logit","inv_sqrt","inv_square","inverse","inverse_spd","is_inf","is_nan","lambert_w0","lambert_wm1","lbeta","lchoose","ldexp","lgamma","linspaced_array","linspaced_int_array","linspaced_row_vector","linspaced_vector","lmgamma","lmultiply","log","log1m","log1m_exp","log1m_inv_logit","log1p","log1p_exp","log_determinant","log_diff_exp","log_falling_factorial","log_inv_logit","log_inv_logit_diff","log_mix","log_modified_bessel_first_kind","log_rising_factorial","log_softmax","log_sum_exp","logit","machine_precision","map_rect","matrix_exp","matrix_exp_multiply","matrix_power","max","mdivide_left_spd","mdivide_left_tri_low","mdivide_right_spd","mdivide_right_tri_low","mean","min","modified_bessel_first_kind","modified_bessel_second_kind","multiply_log","multiply_lower_tri_self_transpose","negative_infinity","norm","not_a_number","num_elements","ode_adams","ode_adams_tol","ode_adjoint_tol_ctl","ode_bdf","ode_bdf_tol","ode_ckrk","ode_ckrk_tol","ode_rk45","ode_rk45_tol","one_hot_array","one_hot_int_array","one_hot_row_vector","one_hot_vector","ones_array","ones_int_array","ones_row_vector","ones_vector","owens_t","polar","positive_infinity","pow","print","prod","proj","qr_Q","qr_R","qr_thin_Q","qr_thin_R","quad_form","quad_form_diag","quad_form_sym","quantile","rank","reduce_sum","reject","rep_array","rep_matrix","rep_row_vector","rep_vector","reverse","rising_factorial","round","row","rows","rows_dot_product","rows_dot_self","scale_matrix_exp_multiply","sd","segment","sin","singular_values","sinh","size","softmax","sort_asc","sort_desc","sort_indices_asc","sort_indices_desc","sqrt","square","squared_distance","step","sub_col","sub_row","sum","svd_U","svd_V","symmetrize_from_lower_tri","tail","tan","tanh","target","tcrossprod","tgamma","to_array_1d","to_array_2d","to_complex","to_matrix","to_row_vector","to_vector","trace","trace_gen_quad_form","trace_quad_form","trigamma","trunc","uniform_simplex","variance","zeros_array","zeros_int_array","zeros_row_vector"]
},contains:[e.C_LINE_COMMENT_MODE,i,e.HASH_COMMENT_MODE,r,{scope:"built_in",
match:/\s(pi|e|sqrt2|log2|log10)(?=\()/,relevance:0},{
match:_.concat(/[<,]\s*/,_.either(...t),/\s*=/),keywords:t},{scope:"keyword",
match:/\btarget(?=\s*\+=)/},{
match:[/~\s*/,_.either(...o),/(?:\(\))/,/\s*T(?=\s*\[)/],scope:{2:"built_in",
4:"keyword"}},{scope:"built_in",keywords:o,
begin:_.concat(/\w*/,_.either(...o),/(_lpdf|_lupdf|_lpmf|_cdf|_lcdf|_lccdf|_qf)(?=\s*[\(.*\)])/)
},{begin:[/~/,/\s*/,_.concat(_.either(...o),/(?=\s*[\(.*\)])/)],scope:{
3:"built_in"}},{
begin:[/~/,/\s*\w+(?=\s*[\(.*\)])/,"(?!.*/\b("+_.either(...o)+")\b)"],scope:{
2:"title.function"}},{scope:"title.function",
begin:/\w*(_lpdf|_lupdf|_lpmf|_cdf|_lcdf|_lccdf|_qf)(?=\s*[\(.*\)])/},{
scope:"number",
match:_.concat(/(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)/,/(?:[eE][+-]?\d+(?:_\d+)*)?i?(?!\w)/),
relevance:0},{scope:"string",begin:/"/,end:/"/}]}}})()
;export default hljsGrammar;

Note: To build the cdn highlight.js files that mimic the discourse ones. Git clone the highlight.js repo then cd into it and run node ./tools/build.js -t cdn :common stan. Assuming node/npm are setup.

3 Likes

Thanks Sean!

I think @martinmodrak is the administrator as well.

the admin group is : https://discourse.mc-stan.org/g/admins
in addition to Martin, @jonah and @syclik would be able to help with the config.

3 Likes

Thanks, @spinkney and @mitzimorris.

So… it’s a bit tough to do since we’re using Discourse’s open-source hosting plan. We don’t have the ability to install plugins.

We can either wait for the updates or…

I’m not sure I’m up for hacking Discourse, but maybe we should?

1 Like

The last post in that thread shows how to do this with a theme. We can try but I think we’d have to rename ‘stan’ so that it doesn’t conflict, something like ‘stan2’.