Class: Pindo::TaskSystem::MultiLineTaskDisplay

Inherits:
Object
  • Object
show all
Defined in:
lib/pindo/module/task/output/multi_line_task_display.rb

Overview

单任务多行显示器管理单个任务的多行滚动显示,采用 FIFO 队列机制

Constant Summary collapse

STATUS_RUNNING =

任务状态枚举

:running
STATUS_SUCCESS =
:success
STATUS_ERROR =
:error
STATUS_PENDING =
:pending

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(task_id, task_name, max_lines: 5) ⇒ MultiLineTaskDisplay

初始化显示器

Parameters:

  • task_id (String)

    任务 ID

  • task_name (String)

    任务名称

  • max_lines (Integer) (defaults to: 5)

    最大显示行数(默认 5)



20
21
22
23
24
25
26
27
28
# File 'lib/pindo/module/task/output/multi_line_task_display.rb', line 20

def initialize(task_id, task_name, max_lines: 5)
  @task_id = task_id
  # 防止任务名称中有换行符破坏显示
  @task_name = task_name.to_s.gsub("\n", " ")
  @max_lines = max_lines
  @status = STATUS_RUNNING
  @lines = []  # 滚动缓冲区(FIFO 队列)
  @mutex = Mutex.new
end

Instance Attribute Details

#linesObject (readonly)

Returns the value of attribute lines.



8
9
10
# File 'lib/pindo/module/task/output/multi_line_task_display.rb', line 8

def lines
  @lines
end

#statusObject (readonly)

Returns the value of attribute status.



8
9
10
# File 'lib/pindo/module/task/output/multi_line_task_display.rb', line 8

def status
  @status
end

#task_idObject (readonly)

Returns the value of attribute task_id.



8
9
10
# File 'lib/pindo/module/task/output/multi_line_task_display.rb', line 8

def task_id
  @task_id
end

#task_nameObject (readonly)

Returns the value of attribute task_name.



8
9
10
# File 'lib/pindo/module/task/output/multi_line_task_display.rb', line 8

def task_name
  @task_name
end

Instance Method Details

#add_line(message) ⇒ Object

添加新行(滚动)新行添加到队列尾部,如果超过 max_lines,则移除最旧的行支持多行消息自动拆分

Parameters:

  • message (String)

    消息内容



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/pindo/module/task/output/multi_line_task_display.rb', line 34

def add_line(message)
  @mutex.synchronize do
    timestamp = Time.now.strftime('%H:%M:%S')
    
    # 处理包含换行符的消息,确保每一行都独立计数
    str_message = message.to_s
    
    # 如果消息为空,至少添加一行空行(或者忽略,这里选择忽略空消息以保持整洁)
    return if str_message.empty?
    
    sub_messages = str_message.split("\n")
    if sub_messages.empty?
       # 处理仅包含换行符的情况
       sub_messages = [""] 
    end

    sub_messages.each do |msg|
      line = "#{timestamp} #{msg}"
      @lines << line
      
      # 保持最多 max_lines 行(FIFO)
      @lines.shift if @lines.size > @max_lines
    end
  end
end

#line_countInteger

计算占用的行数

Returns:

  • (Integer)

    占用的终端行数



156
157
158
159
160
# File 'lib/pindo/module/task/output/multi_line_task_display.rb', line 156

def line_count
  @mutex.synchronize do
    1 + @lines.size  # 任务名称行 + 消息行
  end
end

#mark_error(message) ⇒ Object

标记任务失败

Parameters:

  • message (String)

    错误消息



90
91
92
93
94
95
# File 'lib/pindo/module/task/output/multi_line_task_display.rb', line 90

def mark_error(message)
  @mutex.synchronize do
    @status = STATUS_ERROR
    add_line_unsafe("错误: #{message}")
  end
end

#mark_success(message = nil) ⇒ Object

标记任务成功

Parameters:

  • message (String, nil) (defaults to: nil)

    成功消息



81
82
83
84
85
86
# File 'lib/pindo/module/task/output/multi_line_task_display.rb', line 81

def mark_success(message = nil)
  @mutex.synchronize do
    @status = STATUS_SUCCESS
    add_line_unsafe(message) if message
  end
end

#render(max_lines: nil, max_width: nil) ⇒ String

渲染为终端字符串

Parameters:

  • max_lines (Integer, nil) (defaults to: nil)

    最大显示行数(可选覆盖默认值)

  • max_width (Integer, nil) (defaults to: nil)

    最大显示宽度(可选,用于截断长行以防止换行破坏布局)

Returns:

  • (String)

    终端显示字符串



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/pindo/module/task/output/multi_line_task_display.rb', line 101

def render(max_lines: nil, max_width: nil)
  @mutex.synchronize do
    lines_output = []

    # 状态图标和颜色
    icon = case @status
           when STATUS_RUNNING then ''
           when STATUS_SUCCESS then ''
           when STATUS_ERROR then ''
           when STATUS_PENDING then ''
           else '?'
           end

    color_code = case @status
                 when STATUS_SUCCESS then "\e[32m"  # 绿色
                 when STATUS_ERROR then "\e[31m"    # 红色
                 when STATUS_PENDING then "\e[33m"  # 黄色
                 else "\e[34m"                      # 蓝色(运行中)
                 end

    # 任务名称行
    # 截断任务名称(保留一些空间给图标)
    task_line = "  #{color_code}#{icon} #{@task_name}\e[0m"
    lines_output << task_line

    # 消息行(树形结构)
    display_lines = max_lines ? @lines.last(max_lines) : @lines
    display_lines.each_with_index do |line, index|
      prefix = if index == display_lines.size - 1
                 '└─'  # 最后一行
               else
                 '├─'  # 中间行
               end
      
      full_line = "    #{prefix} #{line}"
      
      # 如果指定了最大宽度,进行截断
      if max_width && max_width > 0
        # 简单截断防止换行
        # 注意:这里假设全角字符占2宽度的情况未被完美处理,但对于防止严重错乱已足够
        if full_line.length > max_width
           # 保留最后 3 个字符为 "..."
           full_line = full_line[0, max_width - 3] + "..."
        end
      end

      lines_output << full_line
    end

    lines_output.join("\n")
  end
end

#update_last_line(message) ⇒ Object

更新最后一行(不滚动,用于进度百分比)为了保证行数计算准确,这里强行将换行符替换为空格

Parameters:

  • message (String)

    更新消息



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/pindo/module/task/output/multi_line_task_display.rb', line 63

def update_last_line(message)
  @mutex.synchronize do
    timestamp = Time.now.strftime('%H:%M:%S')
    
    # 替换换行符,保证只占用一行
    clean_message = message.to_s.gsub("\n", " ")
    line = "#{timestamp} #{clean_message}"

    if @lines.empty?
      @lines << line
    else
      @lines[-1] = line
    end
  end
end