Module: VivlioStarter::CLI::PrismLinesCommands
- Defined in:
- lib/vivlio_starter/cli/prism_lines.rb
Overview
==============================================================================
Module: PrismLinesCommands
Prism.js のコードブロック(
)に行番号を付与するコマンド群。
入力HTMLを解析し、必要なクラスと line-numbers-rows を自動追加して保存する。</p>
<p>提供コマンド:</p>
<pre><code>- prism:lines INPUT_FILE [OUTPUT_FILE]
入力HTML内の Prism.js コードブロックに行番号を追加する。
備考:
- -v/--verbose で詳細ログを表示(ENV には反映しません)。
- OUTPUT_FILE を省略した場合、INPUT_FILE を上書きします。
==============================================================================
Constant Summary collapse
- PRISM_LINES_DESC =
{ short: 'HTMLファイル内のPrism.jsコードブロックに行番号を追加します', long: <<~DESC 指定したHTMLファイル内のPrism.jsコードブロックに行番号を追加します。 引数: INPUT_FILE 入力HTMLファイル(必須) OUTPUT_FILE 出力HTMLファイル(省略可、省略時は入力ファイルを上書き) オプション: -v, --verbose 詳細な処理情報を表示 使用例: vs prism:lines prime.html vs prism:lines prime.html prime_with_lines.html DESC }.freeze
- ALERT_COMMENT_PATTERN =
Prism コメントトークンの [!] マーカーを赤強調クラスに変換する。 コメント記号(# / // / -- / /* / <!--)は保持し、[!] とその前後の空白 1 つを除去する。 旧 post_replace_list.yml の [!] 赤強調ルール(Prism 出力狙い)をここへ移設したもの。
%r{\A(\#|//|--|/\*|<!--)\s*\[!\]\s?}- LINE_NUMBER_EXEMPT_ANCESTORS =
行番号を付けない枠。実行結果(.output)・端末転写(.terminal)・ テキストの図/アスキーアート(.diagram)の
は「コードの提示」ではないため、 Prism 行番号の対象外とする(後処理はコンテナ div 化の後に走るため祖先で判定できる)。
'.output, .terminal, .diagram'- START_LINE_MARKER_PATTERN =
figcaption 末尾の開始行マーカー(例: prime.rb#L22-L25)。 パスに # が含まれ得るため、末尾アンカーで最後のマーカーのみ解釈する。
/#L(\d+)(?:-L(\d+))?\z/
Class Method Summary collapse
-
.add_prism_line_numbers(input_file, output_file = nil) ⇒ Object
Prism.jsの行番号を追加する処理.
-
.build_line_numbers_span(document, lines) ⇒ Object
行数分の line-numbers-rows 構造を生成.
-
.combine_class(original, addition) ⇒ Object
既存クラス文字列に安全にクラスを追加.
-
.consume_start_line_marker(pre) ⇒ Object
figcaption 末尾の #L 開始行マーカーを消費し、行番号ガターの開始値へ変換する。 マーカーは pre_process の範囲 include(または著者手書きの ```ruby:foo.rb#L5)が フェンス情報文字列に載せたもので、VFM を経て figcaption テキストとして届く。 インライン style の counter-reset は prism.css の
counter-reset: linenumber(クラスセレクタ)より優先されるため、CSS 側の変更なしで開始値が変わる。 表示テキストは従来どおりパスのみへ戻す(R8)。. -
.decorate_pre_tag(pre, document) ⇒ Object
要素と内包する
に行番号用クラスと要素を付与. -
.execute_prism_lines(input_file, output_file = nil) ⇒ Object
Samovar/直接呼び出し用エントリポイント.
-
.highlight_alert_comments!(document) ⇒ Object
Prism コメントトークン内の [!] マーカーを赤強調(codered)に変換する。 旧実装は Prism のエンティティ出力 <!-- を文字列マッチしていたが、 Nokogiri のテキストノードではデコード済みの <!-- になるため素の <!-- で書く (旧ルール 2 本=一般コメント+HTML コメントが 1 パターンに統合される)。.
- .included(base) ⇒ Object
-
.line_count(pre) ⇒ Object
コードの行数を返す.
-
.line_number_exempt?(pre) ⇒ Boolean
が行番号免除枠(.output / .terminal / .diagram)の中にあるか。.
-
.log_result(input_file, output_file) ⇒ Object
処理完了メッセージを出力.
-
.parse_html(path) ⇒ Object
HTMLファイルを Nokogiri ドキュメントに変換(HtmlParser に委譲).
-
.remove_legacy_meta(document) ⇒ Object
不要な Content-Type メタタグを除去.
Class Method Details
.add_prism_line_numbers(input_file, output_file = nil) ⇒ Object
Prism.jsの行番号を追加する処理
73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/vivlio_starter/cli/prism_lines.rb', line 73 def add_prism_line_numbers(input_file, output_file = nil) document = parse_html(input_file) highlight_alert_comments!(document) document.css('pre').each do |pre| next if line_number_exempt?(pre) decorate_pre_tag(pre, document) end (document) target = output_file || input_file PostProcessCommands::HtmlParser.save_html_document(target, document) log_result(input_file, target) end |
.build_line_numbers_span(document, lines) ⇒ Object
行数分の line-numbers-rows 構造を生成
156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/vivlio_starter/cli/prism_lines.rb', line 156 def build_line_numbers_span(document, lines) span = Nokogiri::XML::Node.new('span', document) span['aria-hidden'] = 'true' span['class'] = 'line-numbers-rows' lines.times do span.add_child(Nokogiri::XML::Node.new('span', document)) end span end |
.combine_class(original, addition) ⇒ Object
既存クラス文字列に安全にクラスを追加
174 175 176 177 |
# File 'lib/vivlio_starter/cli/prism_lines.rb', line 174 def combine_class(original, addition) classes = [original, addition].compact.reject(&:empty?) classes.join(' ') end |
.consume_start_line_marker(pre) ⇒ Object
figcaption 末尾の #L 開始行マーカーを消費し、行番号ガターの開始値へ変換する。
マーカーは pre_process の範囲 include(または著者手書きの ```ruby:foo.rb#L5)が
フェンス情報文字列に載せたもので、VFM を経て figcaption テキストとして届く。
インライン style の counter-reset は prism.css の counter-reset: linenumber
(クラスセレクタ)より優先されるため、CSS 側の変更なしで開始値が変わる。
表示テキストは従来どおりパスのみへ戻す(R8)。
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/vivlio_starter/cli/prism_lines.rb', line 138 def consume_start_line_marker(pre) figure = pre.parent return unless figure&.name == 'figure' figcaption = figure.at_css('figcaption') return unless figcaption return unless (m = figcaption.text.match(START_LINE_MARKER_PATTERN)) figcaption.content = figcaption.text.sub(START_LINE_MARKER_PATTERN, '') start = m[1].to_i return if start < 1 # 不正な開始値はマーカー除去のみ行い従来動作(1 始まり) pre['data-start'] = start.to_s reset = "counter-reset: linenumber #{start - 1}" pre['style'] = [pre['style'], reset].compact.reject(&:empty?).join('; ') end |
.decorate_pre_tag(pre, document) ⇒ Object
要素と内包する に行番号用クラスと要素を付与
122 123 124 125 126 127 128 129 130 |
# File 'lib/vivlio_starter/cli/prism_lines.rb', line 122 def decorate_pre_tag(pre, document) consume_start_line_marker(pre) pre[:class] = combine_class(pre[:class], 'line-numbers') code = pre.at_css('code') return unless code code[:class] = combine_class(code[:class], 'line-numbers') code.add_child(build_line_numbers_span(document, line_count(pre))) end |
.execute_prism_lines(input_file, output_file = nil) ⇒ Object
Samovar/直接呼び出し用エントリポイント
46 47 48 49 50 51 52 53 54 55 |
# File 'lib/vivlio_starter/cli/prism_lines.rb', line 46 def execute_prism_lines(input_file, output_file = nil) output_file ||= input_file unless File.exist?(input_file) Common.log_error("エラー: 入力ファイル '#{input_file}' が存在しません") return end add_prism_line_numbers(input_file, output_file) end |
.highlight_alert_comments!(document) ⇒ Object
Prism コメントトークン内の [!] マーカーを赤強調(codered)に変換する。 旧実装は Prism のエンティティ出力 <!-- を文字列マッチしていたが、 Nokogiri のテキストノードではデコード済みの <!-- になるため素の <!-- で書く (旧ルール 2 本=一般コメント+HTML コメントが 1 パターンに統合される)。
98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/vivlio_starter/cli/prism_lines.rb', line 98 def highlight_alert_comments!(document) document.css('pre span.token.comment').each do |span| # 記法解説用のネストコード(language-markdown の pre 内)は対象外 next if span.ancestors('pre').any? { |pre| pre['class'].to_s.include?('language-markdown') } text_node = span.children.find(&:text?) next unless text_node next unless (m = text_node.text.match(ALERT_COMMENT_PATTERN)) text_node.content = text_node.text.sub(ALERT_COMMENT_PATTERN) { "#{m[1]} " } span['class'] = "#{span['class']} codered" end end |
.included(base) ⇒ Object
43 |
# File 'lib/vivlio_starter/cli/prism_lines.rb', line 43 def included(base); end |
.line_count(pre) ⇒ Object
コードの行数を返す
58 59 60 |
# File 'lib/vivlio_starter/cli/prism_lines.rb', line 58 def line_count(pre) pre.text.count("\n") + 1 end |
.line_number_exempt?(pre) ⇒ Boolean
が行番号免除枠(.output / .terminal / .diagram)の中にあるか。
117 118 119 |
# File 'lib/vivlio_starter/cli/prism_lines.rb', line 117 def line_number_exempt?(pre) pre.ancestors(LINE_NUMBER_EXEMPT_ANCESTORS).any? end |
.log_result(input_file, output_file) ⇒ Object
処理完了メッセージを出力
180 181 182 183 |
# File 'lib/vivlio_starter/cli/prism_lines.rb', line 180 def log_result(input_file, output_file) suffix = input_file == output_file ? '' : " -> #{output_file}" Common.log_success("行番号付与完了: #{input_file}#{suffix}") end |
.parse_html(path) ⇒ Object
HTMLファイルを Nokogiri ドキュメントに変換(HtmlParser に委譲)
89 90 91 92 |
# File 'lib/vivlio_starter/cli/prism_lines.rb', line 89 def parse_html(path) html = File.read(path, encoding: 'UTF-8') PostProcessCommands::HtmlParser.parse_html_document(html) end |
.remove_legacy_meta(document) ⇒ Object
不要な Content-Type メタタグを除去
169 170 171 |
# File 'lib/vivlio_starter/cli/prism_lines.rb', line 169 def (document) document.css('meta[http-equiv="Content-Type"]').each(&:remove) end |