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

PredatorCZ / PreCore / 461

pending completion
461

push

github-actions-ci

PredatorCZ
update readme

3204 of 6096 relevant lines covered (52.56%)

354.05 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

3
    Copyright 2021-2023 Lukas Cone
4

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

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

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

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

27
const size_t nextTickMS = 100;
28

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

195
        curQue++;
×
196
      }
197

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

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

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

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

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

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

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

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

245
    mustClear = true;
246

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

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

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

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

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

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

281
  TerminateConsoleDontWait();
×
282
}
283

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

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

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

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

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

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

309
void ModifyElements_(element_callback cb) {
2✔
310
  static std::mutex accessMutex;
311
  std::lock_guard lg(accessMutex);
312
  static ElementAPI EAPI;
313
  cb(EAPI);
314
}
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