# frozen_string_literal: truemoduleAsciidoctor# Public: A pluggable adapter for integrating a syntax (aka code) highlighter into AsciiDoc processing.## There are two types of syntax highlighter adapters. The first performs syntax highlighting during the convert phase.# This adapter type must define a highlight? method that returns true. The companion highlight method will then be# called to handle the :specialcharacters substitution for source blocks. The second assumes syntax highlighting is# performed on the client (e.g., when the HTML document is loaded). This adapter type must define a docinfo? method# that returns true. The companion docinfo method will then be called to insert markup into the output document. The# docinfo functionality is available to both adapter types.## Asciidoctor provides several built-in adapters, including coderay, pygments, rouge, highlight.js, html-pipeline, and# prettify. Additional adapters can be registered using SyntaxHighlighter.register or by supplying a custom factory.moduleSyntaxHighlighter# Public: Returns the String name of this syntax highlighter for referencing it in messages and option names.attr_reader:namedefinitializename,backend='html5',opts={}@name=@pre_class=nameend# Public: Indicates whether this syntax highlighter has docinfo (i.e., markup) to insert into the output document at# the specified location.## location - The Symbol representing the location slot (:head or :footer).## Returns a [Boolean] indicating whether the docinfo method should be called for this location.defdocinfo?location;end# Public: Generates docinfo markup for this syntax highlighter to insert at the specified location in the output document.## location - The Symbol representing the location slot (:head or :footer).# doc - The Document in which this syntax highlighter is being used.# opts - A Hash of options that configure the syntax highlighting:# :linkcss - A Boolean indicating whether the stylesheet should be linked instead of embedded (optional).# :cdn_base_url - The String base URL for assets loaded from the CDN.# :self_closing_tag_slash - The String '/' if the converter calling this method emits self-closing tags.## Return the [String] markup to insert.defdocinfolocation,doc,optsraise::NotImplementedError,%(#{SyntaxHighlighter} subclass #{self.class} must implement the ##{__method__} method since #docinfo? returns true)end# Public: Indicates whether highlighting is handled by this syntax highlighter or by the client.## Returns a [Boolean] indicating whether the highlight method should be used to handle the :specialchars substitution.defhighlight?;end# Public: Highlights the specified source when this source block is being converted.## If the source contains callout marks, the caller assumes the source remains on the same lines and no closing tags# are added to the end of each line. If the source gets shifted by one or more lines, this method must return a# tuple containing the highlighted source and the number of lines by which the source was shifted.## node - The source Block to syntax highlight.# source - The raw source text String of this source block (after preprocessing).# lang - The source language String specified on this block (e.g., ruby).# opts - A Hash of options that configure the syntax highlighting:# :callouts - A Hash of callouts extracted from the source, indexed by line number (1-based) (optional).# :css_mode - The Symbol CSS mode (:class or :inline).# :highlight_lines - A 1-based Array of Integer line numbers to highlight (aka emphasize) (optional).# :number_lines - A Symbol indicating whether lines should be numbered (:table or :inline) (optional).# :start_line_number - The starting Integer (1-based) line number (optional, default: 1).# :style - The String style (aka theme) to use for colorizing the code (optional).## Returns the highlighted source String or a tuple of the highlighted source String and an Integer line offset.defhighlightnode,source,lang,optsraise::NotImplementedError,%(#{SyntaxHighlighter} subclass #{self.class} must implement the ##{__method__} method since #highlight? returns true)end# Public: Format the highlighted source for inclusion in an HTML document.## node - The source Block being processed.# lang - The source language String for this Block (e.g., ruby).# opts - A Hash of options that control syntax highlighting:# :nowrap - A Boolean that indicates whether wrapping should be disabled (optional).## Returns the highlighted source [String] wrapped in preformatted tags (e.g., pre and code)defformatnode,lang,optsraise::NotImplementedError,%(#{SyntaxHighlighter} subclass #{self.class} must implement the ##{__method__} method)end# Public: Indicates whether this syntax highlighter wants to write a stylesheet to disk. Only called if both the# linkcss and copycss attributes are set on the document.## doc - The Document in which this syntax highlighter is being used.## Returns a [Boolean] indicating whether the write_stylesheet method should be called.defwrite_stylesheet?doc;end# Public: Writes the stylesheet to support the highlighted source(s) to disk.## doc - The Document in which this syntax highlighter is being used.# to_dir - The absolute String path of the stylesheet output directory.## Returns nothing.defwrite_stylesheetdoc,to_dirraise::NotImplementedError,%(#{SyntaxHighlighter} subclass #{self.class} must implement the ##{__method__} method since #write_stylesheet? returns true)endprivate_class_methoddefself.includedintointo.extendConfigend||:includedmoduleConfig# Public: Statically register the current class in the registry for the specified names.## names - one or more String or Symbol names with which to register the current class as a syntax highlighter# implementation. Symbol arguments are coerced to Strings.## Returns nothing.defregister_for*namesSyntaxHighlighter.registerself,*(names.map{|name|name.to_s})endendmoduleFactory# Public: Associates the syntax highlighter class or object with the specified names.## syntax_highlighter - the syntax highlighter implementation to register# names - one or more String names with which to register this syntax highlighter implementation.## Returns nothing.defregistersyntax_highlighter,*namesnames.each{|name|registry[name]=syntax_highlighter}end# Public: Retrieves the syntax highlighter class or object registered for the specified name.## name - The String name of the syntax highlighter to retrieve.## Returns the SyntaxHighlighter Class or Object instance registered for this name.deffornameregistry[name]end# Public: Resolves the name to a syntax highlighter instance, if found in the registry.## name - The String name of the syntax highlighter to create.# backend - The String name of the backend for which this syntax highlighter is being used (default: 'html5').# opts - A Hash of options providing information about the context in which this syntax highlighter is used:# :doc - The Document for which this syntax highlighter was created.## Returns a [SyntaxHighlighter] instance for the specified name.defcreatename,backend='html5',opts={}if(syntax_hl=self.forname)syntax_hl=syntax_hl.newname,backend,optsif::Class===syntax_hlraise::NameError,%(#{syntax_hl.class} must specify a value for `name')unlesssyntax_hl.namesyntax_hlendendprivatedefregistryraise::NotImplementedError,%(#{Factory} subclass #{self.class} must implement the ##{__method__} method)endendclassCustomFactoryincludeFactorydefinitializeseed_registry=nil@registry=seed_registry||{}endprivatedefregistry@registryendendmoduleDefaultFactoryincludeFactoryprivate@@registry={}defregistry@@registryendunlessRUBY_ENGINE=='opal'publicdefregistersyntax_highlighter,*names@@mutex.owned??names.each{|name|@@registry=@@registry.mergename=>syntax_highlighter}:@@mutex.synchronize{registersyntax_highlighter,*names}end# This method will lazy require and register additional built-in implementations, which include coderay,# pygments, rouge, and prettify. Refer to {Factory#for} for parameters and return value.defforname@@registry.fetchnamedo@@mutex.synchronizedo@@registry.fetchnamedoif(require_path=PROVIDED[name])requirerequire_path@@registry[name]else@@registry=@@registry.mergename=>nilnilendendendendendPROVIDED={'coderay'=>%(#{__dir__}/syntax_highlighter/coderay),'prettify'=>%(#{__dir__}/syntax_highlighter/prettify),'pygments'=>%(#{__dir__}/syntax_highlighter/pygments),'rouge'=>%(#{__dir__}/syntax_highlighter/rouge),}private@@mutex=::Mutex.newendendclassDefaultFactoryProxy<CustomFactoryincludeDefaultFactory# inserts module into ancestors immediately after superclassdefforname@registry.fetch(name){super}endunlessRUBY_ENGINE=='opal'endclassBaseincludeSyntaxHighlighterdefformatnode,lang,optsclass_attr_val=opts[:nowrap]?%(#{@pre_class} highlight nowrap):%(#{@pre_class} highlight)if(transform=opts[:transform])pre={'class'=>class_attr_val}code=lang?{'data-lang'=>lang}:{}transform[pre,code]%(<pre#{pre.map{|k,v|%[ #{k}="#{v}"]}.join}><code#{code.map{|k,v|%[ #{k}="#{v}"]}.join}>#{node.content}</code></pre>)else%(<pre class="#{class_attr_val}"><code#{lang?%[ data-lang="#{lang}"]:''}>#{node.content}</code></pre>)endendendextendDefaultFactory# exports static methodsendendrequire_relative'syntax_highlighter/highlightjs'require_relative'syntax_highlighter/html_pipeline'unlessRUBY_ENGINE=='opal'