Class: Rufio::SyntaxHighlighter

Inherits:
Object
  • Object
show all
Defined in:
lib/rufio/syntax_highlighter.rb

Overview

bat コマンドを使ってファイルのシンタックスハイライトを行うクラス。bat が存在しない場合は available? が false を返し、highlight は [] を返す。mtime ベースのキャッシュを持ち、同じファイルの2回目以降は0msで返す。

Instance Method Summary collapse

Constructor Details

#initializeSyntaxHighlighter

Returns a new instance of SyntaxHighlighter.



8
9
10
11
12
13
# File 'lib/rufio/syntax_highlighter.rb', line 8

def initialize
  @bat_available = bat_available?
  @cache = {}    # file_path => { mtime: Time, lines: Array<String> }
  @pending = {}  # file_path => true(非同期実行中フラグ)
  @mutex = Mutex.new
end

Instance Method Details

#available?Boolean

bat コマンドが利用可能かどうか

Returns:

  • (Boolean)


18
19
20
# File 'lib/rufio/syntax_highlighter.rb', line 18

def available?
  @bat_available
end

#highlight(file_path, max_lines: 50) ⇒ Array<String>

ファイルをシンタックスハイライトして ANSI 付き行の配列を返す(同期版)。bat が使えない場合、ファイルが存在しない場合は []。

Parameters:

  • file_path (String)

    ハイライト対象のファイルパス

  • max_lines (Integer) (defaults to: 50)

    取得する最大行数

Returns:

  • (Array<String>)

    ANSI エスケープコード付きの行配列



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/rufio/syntax_highlighter.rb', line 28

def highlight(file_path, max_lines: 50)
  return [] unless @bat_available
  return [] unless File.exist?(file_path)

  mtime = File.mtime(file_path)
  @mutex.synchronize do
    cache = @cache[file_path]
    return cache[:lines] if cache && cache[:mtime] == mtime
  end

  lines = run_bat(file_path, max_lines)
  @mutex.synchronize { @cache[file_path] = { mtime: mtime, lines: lines } }
  lines
rescue => _e
  []
end

#highlight_async(file_path, max_lines: 50) {|lines| ... } ⇒ Object

ファイルをバックグラウンドスレッドでシンタックスハイライトする(非同期版)。メインループをブロックせず、bat 完了時にコールバックを呼ぶ。キャッシュヒット時はコールバックを即時(同期的に)呼ぶ。同一ファイルへの重複呼び出しは無視する(ペンディングガード)。

Parameters:

  • file_path (String)

    ハイライト対象のファイルパス

  • max_lines (Integer) (defaults to: 50)

    取得する最大行数

Yield Parameters:

  • lines (Array<String>)

    ANSI付き行配列(エラー時は [])



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/rufio/syntax_highlighter.rb', line 53

def highlight_async(file_path, max_lines: 50, &callback)
  return unless @bat_available
  return unless File.exist?(file_path)

  mtime = File.mtime(file_path)

  @mutex.synchronize do
    # キャッシュヒット → 即時コールバック
    cache = @cache[file_path]
    if cache && cache[:mtime] == mtime
      callback&.call(cache[:lines])
      return
    end

    # 既にペンディング中 → 重複スレッドを立てない
    return if @pending[file_path]

    @pending[file_path] = true
  end

  Thread.new do
    begin
      lines = run_bat(file_path, max_lines)
      @mutex.synchronize do
        @cache[file_path] = { mtime: mtime, lines: lines }
        @pending.delete(file_path)
      end
      callback&.call(lines)
    rescue => _e
      @mutex.synchronize { @pending.delete(file_path) }
      callback&.call([])
    end
  end

  nil
end