Skip to content

Commit 4d56a87

Browse files
committed
Terminal/Canvas: Work in progress
1 parent 85da5a4 commit 4d56a87

13 files changed

Lines changed: 309 additions & 162 deletions

File tree

modules/Container/Size2d.mpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,16 @@ export namespace CppUtils::Container
1818

1919
template<std::unsigned_integral T>
2020
Size2d(T, T) -> Size2d<T>;
21+
22+
template<std::unsigned_integral T>
23+
[[nodiscard]] inline constexpr auto operator+(const Size2d<T>& lhs, const Size2d<T>& rhs) noexcept -> auto
24+
{
25+
return Size2d<T>{lhs.x + rhs.x, lhs.y + rhs.y};
26+
}
27+
28+
template<std::unsigned_integral T>
29+
[[nodiscard]] inline constexpr auto operator-(const Size2d<T>& lhs, const Size2d<T>& rhs) noexcept -> auto
30+
{
31+
return Size2d<T>{lhs.x - rhs.x, lhs.y - rhs.y};
32+
}
2133
}

modules/Container/Size3d.mpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,16 @@ export namespace CppUtils::Container
1919

2020
template<std::unsigned_integral T>
2121
Size3d(T, T, T) -> Size3d<T>;
22+
23+
template<std::unsigned_integral T>
24+
[[nodiscard]] inline constexpr auto operator+(const Size3d<T>& lhs, const Size3d<T>& rhs) noexcept -> auto
25+
{
26+
return Size3d<T>{lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z};
27+
}
28+
29+
template<std::unsigned_integral T>
30+
[[nodiscard]] inline constexpr auto operator-(const Size3d<T>& lhs, const Size3d<T>& rhs) noexcept -> auto
31+
{
32+
return Size3d<T>{lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z};
33+
}
2234
}

modules/Log/Logger.mpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@ export module CppUtils.Logger;
66

77
import std;
88
import CppUtils.String;
9-
import CppUtils.Terminal.TextColor;
10-
import CppUtils.Terminal.TextModifier;
11-
import CppUtils.Terminal.Utility;
9+
import CppUtils.Terminal;
1210

1311
// Todo: log le datetime
1412
// Todo: log le stacktrace ( https://en.cppreference.com/w/cpp/utility/stacktrace_entry )

modules/Terminal/Canvas.mpp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ export module CppUtils.Terminal.Canvas;
77
import std;
88
import CppUtils.Container.Size2d;
99
import CppUtils.Terminal.Utility;
10+
import CppUtils.Terminal.Size;
11+
import CppUtils.Terminal.Cursor;
1012

1113
export namespace CppUtils::Terminal
1214
{
@@ -33,16 +35,33 @@ export namespace CppUtils::Terminal
3335
std::puts("");
3436
}
3537

36-
[[nodiscard]] inline constexpr auto getSize() const noexcept
38+
[[nodiscard]] inline constexpr auto getSize() const noexcept -> const auto&
3739
{
3840
return m_size;
3941
}
4042

41-
inline auto fill(char c) noexcept
43+
inline auto fill(char c) noexcept -> void
4244
{
4345
m_buffer.assign(m_size.x * m_size.y, c);
4446
}
4547

48+
[[nodiscard]] inline auto getOrigin() const noexcept -> auto
49+
{
50+
return Container::Size2d<>{0, getTerminalSize().y - m_size.y};
51+
}
52+
53+
inline auto print(Container::Size2d<> position, std::string_view text) noexcept -> void
54+
{
55+
const auto offset = position.x + position.y * m_size.x;
56+
if (offset >= std::size(m_buffer))
57+
return;
58+
59+
std::copy_n(
60+
std::cbegin(text),
61+
std::min(std::size(text), std::size(m_buffer) - offset),
62+
std::begin(m_buffer) + static_cast<std::ptrdiff_t>(offset));
63+
}
64+
4665
inline auto update() -> void
4766
{
4867
{
@@ -54,7 +73,7 @@ export namespace CppUtils::Terminal
5473
const auto buffer = std::string_view{m_buffer};
5574
for (auto lineNb = 0uz; lineNb < m_size.y;)
5675
{
57-
std::fwrite(std::data(buffer.substr(lineNb * m_size.y, m_size.x)), sizeof(decltype(m_buffer)::value_type), m_size.x, stdout);
76+
std::fwrite(std::data(buffer.substr(lineNb * m_size.x, m_size.x)), sizeof(decltype(m_buffer)::value_type), m_size.x, stdout);
5877
if (++lineNb != m_size.y)
5978
std::fwrite("\n", 1, 1, stdout);
6079
}

modules/Terminal/Cursor.mpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
module;
2+
3+
#include <cstdio>
4+
5+
#include <CppUtils/System/Windows.hpp>
6+
7+
export module CppUtils.Terminal.Cursor;
8+
9+
import std;
10+
import CppUtils.Container.Size2d;
11+
import CppUtils.Terminal.RawTerminal;
12+
13+
export namespace CppUtils::Terminal
14+
{
15+
#if defined(OS_WINDOWS)
16+
[[nodiscard]] inline auto getCursorPosition() -> std::expected<Container::Size2d<>, std::string_view>
17+
{
18+
auto consoleScreenBufferInfo = CONSOLE_SCREEN_BUFFER_INFO{};
19+
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &consoleScreenBufferInfo);
20+
return Container::Size2d<>{
21+
static_cast<std::size_t>(consoleScreenBufferInfo.srWindow.X),
22+
static_cast<std::size_t>(consoleScreenBufferInfo.srWindow.Y)};
23+
}
24+
#elif defined(OS_MAC) or defined(OS_LINUX)
25+
[[nodiscard]] inline auto getCursorPosition() -> std::expected<Container::Size2d<>, std::string_view>
26+
{
27+
using namespace std::literals;
28+
29+
auto rawTerminal = RawTerminal{};
30+
std::print("\x1b[6n");
31+
std::fflush(stdout);
32+
33+
const auto response = rawTerminal.read('R');
34+
auto rows = 0, columns = 0;
35+
if (std::sscanf(response.c_str(), "\x1b[%d;%d", &rows, &columns) == 2)
36+
return Container::Size2d<>{static_cast<std::size_t>(columns - 1), static_cast<std::size_t>(rows - 1)};
37+
return std::unexpected{"Cursor position retrieval failure"sv};
38+
}
39+
#endif
40+
41+
#if defined(OS_WINDOWS)
42+
inline auto setCursorPosition(Container::Size2d<> position) -> void
43+
{
44+
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), COORD{position.x, position.y});
45+
}
46+
#elif defined(OS_MAC) or defined(OS_LINUX)
47+
inline auto setCursorPosition([[maybe_unused]] Container::Size2d<> position) -> void
48+
{
49+
std::print("\x1b[{};{}H", position.y + 1, position.x + 1);
50+
}
51+
#endif
52+
}

modules/Terminal/Handle.mpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
module;
2+
3+
#include <CppUtils/System/Windows.hpp>
4+
5+
export module CppUtils.Terminal.Handle;
6+
7+
import std;
8+
import CppUtils.System.Type;
9+
10+
export namespace CppUtils::Terminal
11+
{
12+
#if defined(OS_WINDOWS)
13+
[[nodiscard]] inline auto getTerminalHandle(std::FILE* file) -> System::Handle
14+
{
15+
auto terminalHandle = System::InvalidHandle;
16+
if (file == stdout)
17+
terminalHandle = GetStdHandle(STD_OUTPUT_HANDLE);
18+
else if (file == stderr)
19+
terminalHandle = GetStdHandle(STD_ERROR_HANDLE);
20+
return terminalHandle;
21+
}
22+
23+
[[nodiscard]] inline auto getTerminalHandle(std::ostream& stream) -> System::Handle
24+
{
25+
auto terminalHandle = System::InvalidHandle;
26+
if (&stream == &std::cout)
27+
terminalHandle = GetStdHandle(STD_OUTPUT_HANDLE);
28+
else if (&stream == &std::cerr)
29+
terminalHandle = GetStdHandle(STD_ERROR_HANDLE);
30+
return terminalHandle;
31+
}
32+
#else
33+
[[nodiscard]] inline auto getTerminalHandle([[maybe_unused]] std::FILE* file) -> System::Handle
34+
{
35+
return System::InvalidHandle;
36+
}
37+
38+
[[nodiscard]] inline auto getTerminalHandle([[maybe_unused]] std::ostream& stream) -> System::Handle
39+
{
40+
return System::InvalidHandle;
41+
}
42+
#endif
43+
}

modules/Terminal/ProgressBar.mpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
export module CppUtils.Terminal.ProgressBar;
2+
3+
import std;
4+
import CppUtils.Container.Size2d;
5+
import CppUtils.Terminal.Canvas;
6+
import CppUtils.Terminal.Size;
7+
8+
export namespace CppUtils::Terminal
9+
{
10+
class ProgressBar final
11+
{
12+
public:
13+
inline ProgressBar():
14+
m_canvas{Container::Size2d<>{getTerminalSize().x, 3}}
15+
{
16+
setPercent(0);
17+
}
18+
19+
inline auto setPercent([[maybe_unused]] std::size_t percent) -> void
20+
{
21+
}
22+
23+
private:
24+
Canvas m_canvas;
25+
};
26+
}

modules/Terminal/Size.mpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
module;
2+
3+
#include <CppUtils/System/Windows.hpp>
4+
5+
#if defined(OS_MAC) or defined(OS_LINUX)
6+
# include <sys/ioctl.h>
7+
# include <unistd.h>
8+
#endif
9+
10+
export module CppUtils.Terminal.Size;
11+
12+
import std;
13+
import CppUtils.Container.Size2d;
14+
15+
export namespace CppUtils::Terminal
16+
{
17+
#if defined(OS_WINDOWS)
18+
[[nodiscard]] inline auto getTerminalSize() -> Container::Size2d<>
19+
{
20+
auto consoleScreenBufferInfo = CONSOLE_SCREEN_BUFFER_INFO{};
21+
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &consoleScreenBufferInfo);
22+
return Container::Size2d<>{
23+
static_cast<std::size_t>(consoleScreenBufferInfo.srWindow.Right - consoleScreenBufferInfo.srWindow.Left + 1),
24+
static_cast<std::size_t>(consoleScreenBufferInfo.srWindow.Bottom - consoleScreenBufferInfo.srWindow.Top + 1)};
25+
}
26+
#elif defined(OS_MAC) or defined(OS_LINUX)
27+
[[nodiscard]] inline auto getTerminalSize() -> Container::Size2d<>
28+
{
29+
auto windowsSize = winsize{};
30+
ioctl(STDOUT_FILENO, TIOCGWINSZ, &windowsSize);
31+
return Container::Size2d<>{
32+
windowsSize.ws_col,
33+
windowsSize.ws_row};
34+
}
35+
#endif
36+
}

modules/Terminal/Terminal.mpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,13 @@ export module CppUtils.Terminal;
22

33
export import CppUtils.Terminal.BackgroundColor;
44
export import CppUtils.Terminal.Canvas;
5+
export import CppUtils.Terminal.Cursor;
6+
export import CppUtils.Terminal.Handle;
7+
export import CppUtils.Terminal.ProgressBar;
58
export import CppUtils.Terminal.RawTerminal;
9+
export import CppUtils.Terminal.Size;
610
export import CppUtils.Terminal.TextColor;
711
export import CppUtils.Terminal.TextModifier;
812
export import CppUtils.Terminal.TextStyle;
13+
export import CppUtils.Terminal.Title;
914
export import CppUtils.Terminal.Utility;

modules/Terminal/Title.mpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
module;
2+
3+
#include <cstdio>
4+
5+
#include <CppUtils/System/Windows.hpp>
6+
7+
export module CppUtils.Terminal.Title;
8+
9+
import std;
10+
import CppUtils.Terminal.RawTerminal;
11+
import CppUtils.String.Concept;
12+
import CppUtils.String.Utility;
13+
14+
export namespace CppUtils::Terminal
15+
{
16+
inline auto getTerminalTitle() -> auto
17+
{
18+
#if defined(OS_WINDOWS)
19+
auto title = std::wstring{};
20+
constexpr auto size = 256uz;
21+
title.resize(size);
22+
::GetConsoleTitleW(std::data(title), size);
23+
return title;
24+
#elif defined(OS_MAC) or defined(OS_LINUX)
25+
/*
26+
using namespace std::literals;
27+
28+
auto rawTerminal = RawTerminal{};
29+
std::fwrite("\033]21;?\a", 1, 7, stdout);
30+
std::fflush(stdout);
31+
32+
const auto response = rawTerminal.read('\a');
33+
if (constexpr auto prefix = "\033]21;"sv; response.starts_with(prefix))
34+
return std::string{std::cbegin(response) + std::size(prefix), std::cend(response)};
35+
*/
36+
return std::string{};
37+
#endif
38+
}
39+
40+
inline auto setTerminalTitle(const String::GenericText auto& title) -> void
41+
{
42+
#if defined(OS_WINDOWS)
43+
::SetConsoleTitleW(std::data(title));
44+
#elif defined(OS_MAC) or defined(OS_LINUX)
45+
std::print("\x1B]0;{}\a", title);
46+
std::fflush(stdout);
47+
#endif
48+
}
49+
50+
class Title final
51+
{
52+
public:
53+
inline Title(const String::GenericText auto& title):
54+
m_oldTitle{getTerminalTitle()}
55+
{
56+
setTerminalTitle(title);
57+
}
58+
59+
inline ~Title()
60+
{
61+
setTerminalTitle(m_oldTitle);
62+
}
63+
64+
private:
65+
std::invoke_result_t<decltype(getTerminalTitle)> m_oldTitle;
66+
};
67+
}

0 commit comments

Comments
 (0)