如何为Shiny应用中verbatimTextOutput的多语言代码设置样式并添加行号?
问题描述
我开发了一个Shiny应用,通过verbatimTextOutput分别展示Python和Java代码,现在希望根据编程语言为代码设置对应语法样式,同时添加行号,请问有可行的实现方案吗?
当前应用代码如下:
library(shiny) # Define UI ui <- fluidPage( tags$head( tags$style( HTML( "\n .form-control {\n border-radius: 4px 4px 4px 4px;\n }\n #pythonCode, #javaCode {\n font-size: 14px;\n width: 300px; \n height: 300px; \n max-width: 100%;\n padding: 6px 12px; \n white-space: pre-wrap;\n }\n " ) ) ), titlePanel("Multiple languages example"), sidebarLayout( sidebarPanel( tabsetPanel( tabPanel("Python", verbatimTextOutput("pythonCode")), tabPanel("Java", verbatimTextOutput("javaCode")) ) ), mainPanel() ) ) server <- function(input, output) { output$pythonCode <- renderText({readLines('helloworld.py')}) output$javaCode <- renderText({readLines('helloworld.java')}) } shinyApp(ui = ui, server = server)
当前应用展示效果:
可行实现方案
方案一:使用shinyAce包(推荐)
shinyAce是专为Shiny打造的代码展示/编辑组件,自带多语言语法高亮,支持一键开启行号,实现逻辑简洁,无需手动处理前端细节。
修改后完整代码:
library(shiny) library(shinyAce) # Define UI ui <- fluidPage( tags$head( tags$style( HTML( "\n .form-control {\n border-radius: 4px 4px 4px 4px;\n }\n #pythonCode, #javaCode {\n font-size: 14px;\n width: 300px; \n height: 300px; \n max-width: 100%;\n }\n " ) ) ), titlePanel("Multiple languages example"), sidebarLayout( sidebarPanel( tabsetPanel( tabPanel("Python", aceOutput("pythonCode")), tabPanel("Java", aceOutput("javaCode")) ) ), mainPanel() ) ) server <- function(input, output) { # 渲染Python代码:开启行号,指定语法类型,设置只读 output$pythonCode <- renderAce({ code <- paste(readLines('helloworld.py'), collapse = "\n") aceEditor( value = code, mode = "python", showLineNumbers = TRUE, readOnly = TRUE ) }) # 渲染Java代码:配置同Python output$javaCode <- renderAce({ code <- paste(readLines('helloworld.java'), collapse = "\n") aceEditor( value = code, mode = "java", showLineNumbers = TRUE, readOnly = TRUE ) }) } shinyApp(ui = ui, server = server)
方案二:使用前端highlight.js库
如果不想额外安装R包,可以通过引入highlight.js前端库实现需求,需要手动构建带行号的HTML结构。
修改后完整代码:
library(shiny) # Define UI ui <- fluidPage( tags$head( # 引入本地highlight.js资源(需自行下载文件放入应用的www目录) tags$link(rel = "stylesheet", href = "highlight/styles/github.min.css"), tags$script(src = "highlight/highlight.min.js"), tags$script(src = "highlight/languages/python.min.js"), tags$script(src = "highlight/languages/java.min.js"), tags$script(src = "highlight/highlightjs-line-numbers.min.js"), tags$script(HTML(" // 页面加载后初始化高亮和行号 document.addEventListener('DOMContentLoaded', () => { document.querySelectorAll('pre code').forEach(block => { hljs.highlightElement(block); hljs.lineNumbersBlock(block); }); }); ")), tags$style( HTML( "\n .form-control {\n border-radius: 4px 4px 4px 4px;\n }\n pre.hljs {\n font-size: 14px;\n width: 300px; \n height: 300px; \n max-width: 100%;\n padding: 6px 12px; \n overflow-y: auto;\n }\n /* 行号样式优化 */\n .hljs-ln-numbers {\n text-align: right;\n padding-right: 1em;\n user-select: none;\n opacity: 0.5;\n }\n " ) ) ), titlePanel("Multiple languages example"), sidebarLayout( sidebarPanel( tabsetPanel( tabPanel("Python", htmlOutput("pythonCode")), tabPanel("Java", htmlOutput("javaCode")) ) ), mainPanel() ) ) server <- function(input, output) { # 生成带语法标记的Python代码HTML output$pythonCode <- renderUI({ code <- paste(readLines('helloworld.py'), collapse = "\n") tags$pre(class = "hljs", tags$code(class = "language-python", code) ) }) # 生成带语法标记的Java代码HTML output$javaCode <- renderUI({ code <- paste(readLines('helloworld.java'), collapse = "\n") tags$pre(class = "hljs", tags$code(class = "language-java", code) ) }) } shinyApp(ui = ui, server = server)
注意事项:
- 使用
highlight.js时,需从官方下载对应版本的CSS、JS文件,放入Shiny应用根目录下的www文件夹(无则新建),确保路径匹配代码中的引用。
内容的提问来源于stack exchange,提问作者Lev
相关产品推荐
相关产品推荐

