HAL  v4.5.0-124-g47ab54673
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
user_feedback.cpp
Go to the documentation of this file.
2 
5 
6 #include <algorithm>
7 #include <iomanip>
8 #include <iostream>
9 #include <sstream>
10 #include <sys/ioctl.h>
11 #include <unistd.h>
12 
13 namespace hal
14 {
15  namespace user_feedback
16  {
17  namespace
18  {
20  constexpr int MAX_PLAUSIBLE_TERMINAL_WIDTH = 4096;
21 
23  constexpr int MIN_TERMINAL_WIDTH = 8;
24  } // namespace
25 
26  void report_progress(int percent, const std::string& message)
27  {
28  if (auto* ui_plugin = plugin_manager::get_ui_plugin(); ui_plugin != nullptr)
29  {
30  ui_plugin->set_progress(percent, message);
31  }
32  }
33 
34  LayoutLocker::LayoutLocker() : m_ui_plugin(plugin_manager::get_ui_plugin())
35  {
36  if (m_ui_plugin != nullptr)
37  {
38  m_ui_plugin->set_layout_locker(true);
39  }
40  }
41 
43  {
44  if (m_ui_plugin != nullptr)
45  {
46  m_ui_plugin->set_layout_locker(false);
47  }
48  }
49 
50  std::atomic<u32> ProgressScope::s_depth(0);
51 
52  ProgressScope::ProgressScope(const std::string& message)
53  {
54  if (s_depth++ == 0)
55  {
56  report_progress(0, message);
57  }
58  }
59 
61  {
62  // the progress display treats 100 percent as "done" and dismisses itself, so it must be reported exactly
63  // once per operation
64  if (--s_depth == 0)
65  {
66  report_progress(100, "done");
67  }
68  }
69 
70  ProgressPrinter::ProgressPrinter(const std::string& message, u32 max_detail_size)
71  : m_scope(message), m_message(message), m_printed_progress(0), m_bar_width(0), m_max_detail_size(max_detail_size), m_last_percentage(0), m_terminal_width(get_terminal_width())
72  {
73  if (m_terminal_width > MIN_TERMINAL_WIDTH)
74  {
75  // the bar shares the line with "[] 100%" and, if one was asked for, a detail
76  m_bar_width = m_terminal_width - 7;
77  if (max_detail_size != 0)
78  {
79  m_bar_width -= max_detail_size + 1;
80  }
81  }
82 
83  reset();
84  }
85 
87  {
88  clear();
89  }
90 
91  void ProgressPrinter::set_message(const std::string& message)
92  {
93  m_message = message;
94  report_progress(m_last_percentage, m_message);
95  }
96 
97  void ProgressPrinter::report(float progress, const std::string& detail)
98  {
99  progress = std::clamp(progress, 0.0f, 1.0f);
100  m_last_percentage = (int)(progress * 100.0f);
101 
102  // 100 percent dismisses the progress display of the user interface, which is up to the ProgressScope
103  // bracketing the operation rather than to a report from within it
104  report_progress(std::min(m_last_percentage, 99), m_message);
105 
106  if (m_terminal_width <= MIN_TERMINAL_WIDTH)
107  {
108  return;
109  }
110 
111  const u32 pos = (u32)(m_bar_width * progress);
112  if (pos <= m_printed_progress && m_last_detail == detail)
113  {
114  // nothing about the bar would change, so leave the terminal alone
115  return;
116  }
117 
118  m_last_detail = detail;
119  m_printed_progress = pos;
120 
121  std::string bar;
122  if (pos)
123  {
124  bar += std::string(pos, '=');
125  }
126  if (pos < m_bar_width)
127  {
128  bar += '>';
129  }
130  if (pos + 1 < m_bar_width)
131  {
132  bar += std::string(m_bar_width - pos - 1, ' ');
133  }
134 
135  auto printed_detail = detail;
136  if (printed_detail.size() > m_max_detail_size)
137  {
138  printed_detail = (m_max_detail_size <= 3) ? std::string(m_max_detail_size, '.') : printed_detail.substr(0, m_max_detail_size - 3) + "...";
139  }
140 
141  std::stringstream str;
142  str << "[" << bar << "] " << std::right << std::setw(3) << m_last_percentage << '%';
143  if (!printed_detail.empty())
144  {
145  str << " " << printed_detail;
146  }
147 
148  const auto output = str.str();
149  std::cerr << output;
150  if (output.size() < (u32)m_terminal_width)
151  {
152  std::cerr << std::string(m_terminal_width - output.size(), ' ');
153  }
154  std::cerr << "\r" << std::flush;
155  }
156 
158  {
159  if (m_terminal_width <= MIN_TERMINAL_WIDTH)
160  {
161  return;
162  }
163  std::cerr << std::string(m_terminal_width, ' ') << "\r" << std::flush;
164  }
165 
167  {
168  m_printed_progress = 0;
169 
170  // no detail can ever compare equal to this, so the next report draws the bar in any case
171  m_last_detail = std::string("\0redraw", 7);
172  }
173 
174  int ProgressPrinter::get_terminal_width()
175  {
176  struct winsize size;
177  if (ioctl(STDERR_FILENO, TIOCGWINSZ, &size) < 0)
178  {
179  return -1;
180  }
181  if (size.ws_col > MAX_PLAUSIBLE_TERMINAL_WIDTH)
182  {
183  return -1;
184  }
185  return size.ws_col;
186  }
187  } // namespace user_feedback
188 } // namespace hal
u32 size
virtual void set_layout_locker(bool enable)=0
void set_message(const std::string &message)
ProgressPrinter(const std::string &message, u32 max_detail_size=0)
void report(float progress, const std::string &detail="")
ProgressScope(const std::string &message)
uint32_t u32
Definition: defines.h:41
UIPluginInterface * get_ui_plugin()
void report_progress(int percent, const std::string &message)
Definition: defines.h:45