Class: Mighost::PlainUI

Inherits:
Object
  • Object
show all
Includes:
Formatting
Defined in:
lib/mighost/plain_ui.rb

Overview

PlainUI is the default UI adapter for mighost. It outputs plain, uncolored text suitable for any terminal.

To provide custom (rich) output, replace this adapter:

Mighost.ui = YourCustomUI.new

Adapter interface:

render_orphans(orphans)
render_records(records, limit:, total_count:)
render_recoverable_list(orphans)
render_scan_details(details)
render_scan_results(captured:, git_recovered:, worktree_recovered:, branch:, sha:)
render_dismiss_preview(versions, orphan_map)
render_dismissed_list(dismissed_snapshots)
confirm?(prompt) -> Boolean
confirm_each?(orphan) -> :yes, :no, :all, :quit
confirm_dismiss?(version, name) -> :yes, :no, :all, :quit
success(msg), error(msg), warning(msg), info(msg), hint(msg)

Instance Method Summary collapse

Methods included from Formatting

format_age, format_captured_at, format_name, format_recovery, format_version, parse_version_range, truncate

Instance Method Details

#confirm?(prompt) ⇒ Boolean

Returns:

  • (Boolean)


159
160
161
162
163
# File 'lib/mighost/plain_ui.rb', line 159

def confirm?(prompt)
  print "\n#{prompt} [y/N] "
  response = $stdin.gets.chomp.downcase
  response == "y"
end

#confirm_dismiss?(version, name) ⇒ Boolean

Returns:

  • (Boolean)


174
175
176
177
# File 'lib/mighost/plain_ui.rb', line 174

def confirm_dismiss?(version, name)
  print "\nDismiss #{format_version(version)} #{name}? [y/n/a/q] "
  parse_multi_choice
end

#confirm_each?(orphan) ⇒ Boolean

Returns:

  • (Boolean)


165
166
167
168
169
170
171
172
# File 'lib/mighost/plain_ui.rb', line 165

def confirm_each?(orphan)
  name = orphan.filename || "(unknown)"
  version = format_version(orphan.version)
  recovery = format_recovery(orphan.recovery_source)

  print "\nRollback #{version} #{name} [#{recovery}]? [y/n/a/q] "
  parse_multi_choice
end

#error(msg) ⇒ Object



183
184
185
# File 'lib/mighost/plain_ui.rb', line 183

def error(msg)
  puts msg
end

#hint(msg) ⇒ Object



195
196
197
# File 'lib/mighost/plain_ui.rb', line 195

def hint(msg)
  puts "Hint: #{msg}"
end

#info(msg) ⇒ Object



191
192
193
# File 'lib/mighost/plain_ui.rb', line 191

def info(msg)
  puts msg
end

#render_dismiss_preview(versions, orphan_map) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/mighost/plain_ui.rb', line 127

def render_dismiss_preview(versions, orphan_map)
  puts "\nFound #{versions.count} orphaned migration(s) to dismiss:\n"
  preview_count = 10
  versions.first(preview_count).each do |v|
    puts "  #{v}  (#{format_version(v)})"
  end
  if versions.count > preview_count
    remaining = versions.count - preview_count
    puts "  ... and #{remaining} more up to #{format_version(versions.last)}"
  end
  puts ""
end

#render_dismiss_remaining(versions, orphan_map) ⇒ Object



140
141
142
143
144
145
146
# File 'lib/mighost/plain_ui.rb', line 140

def render_dismiss_remaining(versions, orphan_map)
  puts "\nDismissing all remaining:"
  versions.each do |v|
    o = orphan_map[v]
    puts "  #{v} - #{o&.filename || "(unknown)"}"
  end
end

#render_dismissed_list(dismissed_snapshots) ⇒ Object



148
149
150
151
152
153
154
155
156
157
# File 'lib/mighost/plain_ui.rb', line 148

def render_dismissed_list(dismissed_snapshots)
  puts "\nDismissed migrations (#{dismissed_snapshots.count}):\n\n"
  dismissed_snapshots.each do |version, snapshot|
    name = snapshot&.filename.presence || "(unknown)"
    dismissed_at = snapshot&.dismissed_at
    date_str = dismissed_at ? " (dismissed #{dismissed_at[0, 10]})" : ""
    puts "  #{version} - #{name}#{date_str}"
  end
  puts "\nTip: Use 'rails mighost:undismiss VERSION=x' to restore."
end

#render_orphans(orphans) ⇒ Object



30
31
32
33
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
59
60
# File 'lib/mighost/plain_ui.rb', line 30

def render_orphans(orphans)
  if orphans.empty?
    info "No orphaned migrations found."
    return
  end

  actionable, suggested = orphans.partition(&:actionable?)

  recoverable_count = orphans.count(&:recoverable?)
  suggested_count = suggested.count

  header_parts = ["#{orphans.count} total", "#{recoverable_count} recoverable"]
  header_parts << "#{suggested_count} suggested to dismiss" if suggested_count.positive?
  puts "\nOrphaned migrations (#{header_parts.join(", ")}):\n\n"

  actionable.each { |o| puts "  #{orphan_line(o)}" }

  if actionable.any? && suggested.any?
    puts "\n  Suggested to dismiss (#{suggested.count} old, unrecoverable):\n"
  end

  suggested.each { |o| puts "  #{orphan_line(o)}" }

  if suggested_count.positive?
    puts "\nTip: Run 'rails mighost:dismiss OLD=1' to bulk-dismiss the #{suggested_count} old migrations."
  end

  if recoverable_count.positive?
    puts "\nTip: Run 'rails mighost:rollback' to rollback recoverable migrations."
  end
end

#render_records(records, limit: nil, total_count: nil) ⇒ Object



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
89
90
91
92
93
94
95
# File 'lib/mighost/plain_ui.rb', line 62

def render_records(records, limit: nil, total_count: nil)
  if records.empty?
    info "No migration records stored."
    return
  end

  count_text = if limit && total_count && total_count > records.count
    "#{records.count} of #{total_count}"
  else
    records.count.to_s
  end

  output = []
  output << "\nMigration records (#{count_text}):\n\n"
  records.each do |record|
    version = format_version(record.version)
    name = format_name(record.filename)
    branch = truncate(record.branch_name || "-", 25)
    sha = record.git_sha || "-"
    captured = format_captured_at(record.migrated_at)
    author = truncate(record.author_name || "-", 20)

    output << "  #{version}  #{name.ljust(42)}  #{branch.ljust(27)}  #{sha.ljust(14)}  #{captured}  #{author}\n"
  end

  text = output.join

  if $stdout.tty? && records.size > 30 && !limit
    pager = ENV["PAGER"] || "less"
    IO.popen(pager, "w") { |io| io.puts text }
  else
    print text
  end
end

#render_recoverable_list(orphans) ⇒ Object



97
98
99
100
101
102
103
# File 'lib/mighost/plain_ui.rb', line 97

def render_recoverable_list(orphans)
  puts "\nRecoverable orphaned migrations:"
  orphans.each do |orphan|
    name = orphan.filename || "(unknown)"
    puts "  #{orphan.version} - #{name}"
  end
end

#render_scan_details(details) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/mighost/plain_ui.rb', line 105

def render_scan_details(details)
  details.each do |detail|
    case detail[:type]
    when :captured
      info "Captured: #{detail[:filename]}"
    when :git_recovered
      info "Git recovered: #{detail[:filename]} (from #{detail[:branch]})"
    when :worktree_recovered
      info "Worktree recovered: #{detail[:filename]} (from #{detail[:branch]})"
    end
  end
end

#render_scan_results(captured:, git_recovered:, worktree_recovered:, branch:, sha:) ⇒ Object



118
119
120
121
122
123
124
125
# File 'lib/mighost/plain_ui.rb', line 118

def render_scan_results(captured:, git_recovered:, worktree_recovered:, branch:, sha:)
  puts ""
  success "Scan complete:"
  info "  Captured #{captured} migration(s) from files"
  info "  Recovered #{git_recovered} orphan(s) from git history"
  info "  Recovered #{worktree_recovered} orphan(s) from worktrees" if worktree_recovered > 0
  info "  Context: #{branch} @ #{sha}"
end

#success(msg) ⇒ Object



179
180
181
# File 'lib/mighost/plain_ui.rb', line 179

def success(msg)
  puts msg
end

#warning(msg) ⇒ Object



187
188
189
# File 'lib/mighost/plain_ui.rb', line 187

def warning(msg)
  puts msg
end