• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PredatorCZ / PreCore / 460

pending completion
460

push

github-actions-ci

PredatorCZ
try fix coverage

3204 of 6095 relevant lines covered (52.57%)

354.19 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

11.46
/src/cli/console.cpp
1
/*  Spike is universal dedicated module handler
2
    Part of PreCore project
3

4
    Copyright 2021-2022 Lukas Cone
5

6
    Licensed under the Apache License, Version 2.0 (the "License");
7
    you may not use this file except in compliance with the License.
8
    You may obtain a copy of the License at
9

10
        http://www.apache.org/licenses/LICENSE-2.0
11

12
    Unless required by applicable law or agreed to in writing, software
13
    distributed under the License is distributed on an "AS IS" BASIS,
14
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
    See the License for the specific language governing permissions and
16
    limitations under the License.
17
*/
18

19
#include "spike/app/console.hpp"
20
#include "spike/master_printer.hpp"
21
#include "spike/type/tchar.hpp"
22
#include <algorithm>
23
#include <csignal>
24
#include <mutex>
25
#include <thread>
26
#include <vector>
27

28
const size_t nextTickMS = 100;
29

30
const char8_t *loopchars[] = {
31
    u8"\u2807", u8"\u280B", u8"\u2819", u8"\u2838", u8"\u2834", u8"\u2826",
32
};
33

34
const char8_t *barchars[] = {
35
    u8"\u2801", u8"\u2803", u8"\u2807", u8"\u2847",
36
    u8"\u284F", u8"\u285F", u8"\u287F", u8"\u28FF",
37
};
38

39
void ProgressBar::PrintLine() {
×
40
  const size_t width = 50;
41
  const float normState = std::min(curitem * itemDelta, 1.f);
×
42
  const size_t state = normState * width;
×
43
  es::Print(label.data());
44
  es::Print("\033[38;2;168;204;140m");
45

46
  for (size_t i = 0; i < state; i++) {
×
47
#ifdef USEWIN
48
    es::Print("#");
49
#else
50
    es::Print(u8"\u25A0");
51
#endif
52
  }
53

54
  for (size_t i = state; i < width; i++) {
×
55
    es::Print(" ");
56
  }
57

58
  char percBuffer[16]{};
×
59
  snprintf(percBuffer, sizeof(percBuffer), "\033[0m %3u%% ",
×
60
           uint32(normState * 100));
×
61
  es::Print(percBuffer);
62
}
63

64
void DetailedProgressBar::PrintLine() {
×
65
  const size_t goal = curitem;
66
  const size_t width = 50;
67
  const size_t parts = 8;
68
  const float normStateGoal = std::min(goal * itemDelta, 1.f);
×
69
  float normState = normStateGoal;
70

71
  if (lastItem < normStateGoal) {
×
72
    lastItem += (normStateGoal - lastItem) / 5;
×
73
    normState = lastItem;
74
  } else {
75
    lastItem = normStateGoal;
×
76
  }
77

78
  const size_t stateMacro = normState * width;
×
79
  const size_t state = size_t(normState * width * parts) % parts;
×
80

81
  es::Print(label.data());
82
  es::Print("\033[38;2;168;204;140m");
83

84
  for (size_t i = 0; i < stateMacro; i++) {
×
85
    es::Print(barchars[7]);
×
86
  }
87

88
  if (state) {
×
89
    es::Print(barchars[state]);
×
90
  }
91

92
  for (size_t i = stateMacro + bool(state); i < width; i++) {
×
93
    es::Print(" ");
94
  }
95

96
  char percBuffer[16]{};
×
97
  snprintf(percBuffer, sizeof(percBuffer), "\033[0m %3u%% ",
×
98
           uint32(normState * 100));
×
99
  es::Print(percBuffer);
100
}
101

102
void LoadingBar::PrintLine() {
×
103
  if (!state) {
×
104
    const size_t loopTick = (innerTick / 100) % 6;
×
105
    es::Print(loopchars[loopTick]);
×
106
    es::Print(" ");
107
  } else if (state == 1) {
×
108
    es::Print(u8"\033[38;2;168;220;140m\u2714 \033[0m");
109
  } else {
110
    es::Print(u8"\u274C ");
111
  }
112

113
  es::Print(payload.data());
114
  innerTick += nextTickMS;
×
115
}
116

117
struct LineMsg {
3✔
118
  std::unique_ptr<LogLine> newLine;
119
  LogLine *line = nullptr;
120
  bool after = false;
121

122
  LineMsg(std::unique_ptr<LogLine> &&item) : newLine(std::move(item)) {}
1✔
123
  LineMsg(std::unique_ptr<LogLine> &&item, LogLine *point, bool after_)
124
      : newLine(std::move(item)), line(point), after(after_) {}
×
125
  LineMsg(LogLine *point) : line(point) {}
1✔
126
  LineMsg(LogLine *point, bool release) : line(point), after(release) {}
×
127
};
128

129
static std::vector<es::print::Queuer> messageQueues[2];
130
static std::vector<std::unique_ptr<LogLine>> lineStack;
131
static std::vector<LineMsg> lineQueue[2];
132
static std::atomic_bool currentlyUsedMessageQueue;
133
static std::atomic_bool currentlyUsedLineQueue;
134
static std::atomic_bool stopLogger;
135
static std::atomic_bool eraseAllLines;
136
static std::thread logger;
137
static std::atomic_uint8_t printDetail{0};
138
static std::atomic_uint64_t newPrintDetailSince{0};
139

140
void ReceiveQueue(const es::print::Queuer &que) {
×
141
  messageQueues[currentlyUsedMessageQueue].push_back(que);
×
142
}
143

144
void MakeLogger() {
×
145
  size_t innerTick = 0;
146
  currentlyUsedMessageQueue = false;
147
  currentlyUsedLineQueue = false;
148
  bool mustClear = false;
149

150
  while (!stopLogger) {
×
151
    if (mustClear) {
×
152
      es::Print("\033[J");
153
      mustClear = false;
154
    }
155

156
    if (bool mqo = currentlyUsedMessageQueue; !messageQueues[mqo].empty()) {
×
157
      currentlyUsedMessageQueue = !mqo;
×
158
      uint8 fullDetail = printDetail;
159
      uint64 newDetailSince = newPrintDetailSince.exchange(0);
160
      size_t curQue = 0;
161

162
      for (auto &l : messageQueues[mqo]) {
×
163
        uint8 detail = newDetailSince <= curQue ? fullDetail : fullDetail >> 4;
×
164
        bool colored = detail & 1;
165
        if (colored) {
×
166
          using es::print::MPType;
167
          switch (l.type) {
×
168
          case MPType::ERR:
169
            es::Print(u8"\033[38;2;255;50;50m\u26D4 ");
170
            break;
171
          case MPType::INF:
172
            es::Print(u8"\033[38;2;50;120;255m \u2139 ");
173
            break;
174
          case MPType::WRN:
175
            es::Print(u8"\033[38;2;255;255;50m\u26A0  ");
176
            break;
177
          default:
178
            es::Print(u8"\033[0m   ");
179
            colored = false;
180
            break;
181
          }
182
        }
183

184
        if (detail & 2) {
×
185
          char threadBuffer[16]{};
×
186
          snprintf(threadBuffer, sizeof(threadBuffer), "[0x%.8X] ", l.threadId);
×
187
          es::Print(threadBuffer);
188
        }
189

190
        es::Print(l.payload.data());
191

192
        if (colored) {
×
193
          es::Print(u8"\033[0m");
194
        }
195

196
        curQue++;
×
197
      }
198

199
      messageQueues[mqo].clear();
200
    }
201

202
    if (eraseAllLines) {
×
203
      lineQueue[0].clear();
204
      lineQueue[1].clear();
205
      lineStack.clear();
206
      eraseAllLines = false;
207
    }
208

209
    if (bool lqo = currentlyUsedLineQueue; !lineQueue[lqo].empty()) {
×
210
      currentlyUsedLineQueue = !lqo;
×
211

212
      for (auto &l : lineQueue[lqo]) {
×
213
        if (l.line) {
×
214
          if (l.newLine) {
×
215
            auto found = std::find_if(
×
216
                lineStack.begin(), lineStack.end(),
217
                [&](auto &item_) { return item_.get() == l.line; });
×
218
            lineStack.insert(std::next(found, l.after), std::move(l.newLine));
×
219
          } else {
220
            if (l.after) {
×
221
              l.line->PrintLine();
×
222
              es::Print("\n");
223
            }
224

225
            lineStack.erase(std::find_if(
×
226
                lineStack.begin(), lineStack.end(),
227
                [&](auto &item_) { return item_.get() == l.line; }));
×
228
          }
229
        } else {
230
          lineStack.emplace_back(std::move(l.newLine));
×
231
        }
232
      }
233

234
      lineQueue[lqo].clear();
235
    }
236

237
    for (auto &l : lineStack) {
×
238
      l->PrintLine();
×
239
      es::Print("\n");
240
    }
241

242
    for (size_t i = 0; i < lineStack.size(); i++) {
×
243
      es::Print("\033[A");
244
    }
245

246
    mustClear = true;
247

248
    std::this_thread::sleep_for(std::chrono::milliseconds(nextTickMS));
×
249
    innerTick += nextTickMS;
250
  }
251
}
252

253
void TerminateConsoleDontWait() {
×
254
  eraseAllLines = true;
255
  stopLogger = true;
256
  if (logger.joinable()) {
×
257
    logger.join();
×
258
  }
259

260
  es::Print("\033[?25h"); // Enable cursor
261
}
262

263
void InitConsole() {
×
264
  es::Print("\033[?25l"); // Disable cursor
265
  es::print::AddQueuer(ReceiveQueue);
×
266
  logger = std::thread{MakeLogger};
×
267
  pthread_setname_np(logger.native_handle(), "console_logger");
×
268
  auto terminate = [](int sig) {
269
    TerminateConsoleDontWait();
270
    std::exit(sig);
271
  };
272

273
  std::signal(SIGTERM, terminate);
×
274
  std::signal(SIGABRT, terminate);
×
275
  std::signal(SIGINT, terminate);
×
276
}
277

278
void TerminateConsole() {
×
279
  while (!messageQueues[0].empty() && !messageQueues[1].empty()) {
280
  }
281

282
  TerminateConsoleDontWait();
×
283
}
284

285
void ConsolePrintDetail(uint8 detail) {
×
286
  newPrintDetailSince = messageQueues[currentlyUsedMessageQueue].size();
×
287
  uint8 oldDetail = printDetail;
288
  printDetail = detail | oldDetail << 4;
×
289
}
290

291
void ElementAPI::Append(std::unique_ptr<LogLine> &&item) {
1✔
292
  lineQueue[currentlyUsedLineQueue].emplace_back(std::move(item));
1✔
293
}
1✔
294

295
void ElementAPI::Remove(LogLine *item) {
1✔
296
  lineQueue[currentlyUsedLineQueue].emplace_back(item);
1✔
297
}
1✔
298

299
void ElementAPI::Release(LogLine *line) {
×
300
  lineQueue[currentlyUsedLineQueue].emplace_back(line, true);
×
301
}
302

303
void ElementAPI::Clean() { eraseAllLines = true; }
×
304

305
void ElementAPI::Insert(std::unique_ptr<LogLine> &&item, LogLine *where,
×
306
                        bool after) {
307
  lineQueue[currentlyUsedLineQueue].emplace_back(std::move(item), where, after);
×
308
}
309

310
void ModifyElements_(element_callback cb) {
2✔
311
  static std::mutex accessMutex;
312
  std::lock_guard lg(accessMutex);
313
  static ElementAPI EAPI;
314
  cb(EAPI);
315
}
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc