Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .github/workflows/windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ jobs:
- name: Checkout code
uses: actions/checkout@v2

- name: Build and test
- name: Build
run: |
ci\compile_test.bat
examples\Release\colors.exe
ci\compile_test.ps1
- name: Test
run: ci\test.ps1
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ cmake-build-release-cygwin/
cmake-build-debug/
cmake-build-debug-visual-studio/
cmake-build-debug-cygwin/
cmake-build-minsizerel/
cmake-build-relwithdebinfo/
.idea/

# cmake
Expand Down
8 changes: 0 additions & 8 deletions ci/compile_test.bat

This file was deleted.

11 changes: 11 additions & 0 deletions ci/compile_test.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#cmake -DCMAKE_INSTALL_PREFIX=.\inst .
cmake .
cmake --build . --config Release
cmake --install . --config Release
ctest --output-on-failure

# Install on windows is complicated and not like on linux
#cd tests\test-standalone
#cmake -DCMAKE_PREFIX_PATH=%cd%\..\inst .
#cmake --build . --config Release
#cd
10 changes: 10 additions & 0 deletions ci/test.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
echo "running example programs"
.\examples\Release\colors.exe
.\tests\Release\test_terminal.exe
.\examples\Release\read_stdin.exe

echo "testing read_stind"
if ((echo test | .\examples\Release\read_stdin.exe) -ne "Input from stdin: test") {
echo "read_stdin gave wrong output"
exit 1
}
7 changes: 7 additions & 0 deletions ci/tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ set -ex

./tests/test_terminal
./examples/colors
./examples/read_stdin

echo "testing stdin example"
if [[ $(echo test | ./examples/read_stdin) != "Input from stdin: test" ]]; then
echo "stdin example returned wrong input"
exit 1
fi

echo "Expected to succeed:"
./examples/colors < README.md
Expand Down
20 changes: 20 additions & 0 deletions cpp-terminal/input.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <chrono>
#include <cpp-terminal/base.hpp>
#include <cpp-terminal/input.hpp>
#include <thread>
#include "private/platform.hpp"
Expand Down Expand Up @@ -183,3 +184,22 @@ int Term::read_key0() {
return c;
}
}

// returns the whole input from STDIN as string
std::string Term::read_stdin() {
std::string file;
char c;
while (true) {
c = Private::read_raw_stdin();
if (c == 0x04) { // check for end of transmission signal
return file;
} else {
file += c;
}
}
}
std::string Term::read_stdin_alone() {
// temporarily enable raw mode
Term::Terminal term(false, true, false, false);
return Term::read_stdin();
}
16 changes: 15 additions & 1 deletion cpp-terminal/input.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include <string>

namespace Term {
enum Key {
Expand Down Expand Up @@ -40,11 +41,24 @@ enum Key {
};

// Waits for a key press, translates escape codes
// if Term:Terminal is not enabling the keyboard it'll loop for infinity
int read_key();

// If there was a key press, returns the translated key from escape codes,
// otherwise returns 0. If the escape code is not supported, returns a
// otherwise returns 0. If the escape code is not supported it returns a
// negative number.
// if Term::Terminal is not enabling the keyboard it'll always return 0
int read_key0();

// returns the stdin as a string
// waits until the EOT signal is send
// if Term::Terminal is not enabling the keyboard this function will wait until
// the user presses CTRL+D (which sends the EOT signal)
std::string read_stdin();

// returns stdin as a string, Term::Terminal is used to enable input to make the
// function non-blocking, use Term::read_stdin() when Term::Terminal is already
// created
std::string read_stdin_alone();

} // namespace Term
40 changes: 22 additions & 18 deletions cpp-terminal/private/platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,22 +68,24 @@ bool Term::Private::get_term_size(int& rows, int& cols) {
}
#endif
}
char Term::Private::read_raw_stdin() {
int c = getchar();
if (c >= 0) {
return c;
} else if (c == EOF) {
// In non-raw (blocking) mode this happens when the input file
// ends. In such a case, return the End of Transmission (EOT)
// character (Ctrl-D)
return 0x04;
} else {
throw std::runtime_error("getchar() failed");
}
}

bool Term::Private::read_raw(char* s) {
// TODO: What if the keyboard is not initialized?
if (false) {
int c = getchar();
if (c >= 0) {
*s = c;
} else if (c == EOF) {
// In non-raw (blocking) mode this happens when the input file
// ends. In such a case, return the End of Transmission (EOT)
// character (Ctrl-D)
*s = 0x04;
} else {
throw std::runtime_error("getchar() failed");
}
return true;
// do nothing when TTY is not connected
if (!is_stdin_a_tty()) {
return false;
}
#ifdef _WIN32
HANDLE hin = GetStdHandle(STD_INPUT_HANDLE);
Expand Down Expand Up @@ -144,8 +146,9 @@ Term::Private::BaseTerminal::~BaseTerminal() noexcept(false) {
Term::Private::BaseTerminal::BaseTerminal(bool enable_keyboard,
bool /*disable_ctrl_c*/)
: keyboard_enabled{enable_keyboard} {
// Uncomment this to silently disable raw mode for non-tty
// if (keyboard_enabled) keyboard_enabled = is_stdin_a_tty();
// silently disable raw mode for non-tty
if (keyboard_enabled)
keyboard_enabled = is_stdin_a_tty();
out_console = is_stdout_a_tty();
if (out_console) {
hout = GetStdHandle(STD_OUTPUT_HANDLE);
Expand Down Expand Up @@ -187,8 +190,9 @@ Term::Private::BaseTerminal::BaseTerminal(bool enable_keyboard,
bool disable_ctrl_c)
: orig_termios{std::make_unique<termios>()},
keyboard_enabled{enable_keyboard} {
// Uncomment this to silently disable raw mode for non-tty
// if (keyboard_enabled) keyboard_enabled = is_stdin_a_tty();
// silently disable raw mode for non-tty
if (keyboard_enabled)
keyboard_enabled = is_stdin_a_tty();
if (keyboard_enabled) {
if (tcgetattr(STDIN_FILENO, orig_termios.get()) == -1) {
throw std::runtime_error("tcgetattr() failed");
Expand Down
2 changes: 2 additions & 0 deletions cpp-terminal/private/platform.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,6 @@ class BaseTerminal {
virtual ~BaseTerminal() noexcept(false);
};

char read_raw_stdin();

} // namespace Term::Private
3 changes: 3 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ target_link_libraries(keys cpp-terminal)
add_executable(colors colors.cpp)
target_link_libraries(colors cpp-terminal)

add_executable(read_stdin read_stdin.cpp)
target_link_libraries(read_stdin cpp-terminal)

# enable warnings and set compile features
foreach(target kilo menu menu_window keys colors)
# Force Microsoft Visual Studio to decode sources files in UTF-8
Expand Down
6 changes: 6 additions & 0 deletions examples/keys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ using Term::Terminal;

int main() {
try {
// check if the terminal is capable of handling input
if (!Term::is_stdin_a_tty()) {
std::cout << "The terminal is not attached to a TTY and therefore "
"can't catch user input. Exiting...\n";
return 1;
}
Terminal term(true, true, true, false);
int rows{}, cols{};
Term::get_term_size(rows, cols);
Expand Down
6 changes: 6 additions & 0 deletions examples/kilo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -929,6 +929,12 @@ int main(int argc, char* argv[]) {
// being called when exception happens and the terminal is not put into
// correct state.
try {
// check if the terminal is capable of handling input
if (!Term::is_stdin_a_tty()) {
std::cout << "The terminal is not attached to a TTY and therefore "
"can't catch user input. Exiting...\n";
return 1;
}
Terminal term(true, true, false, false);
initEditor();
if (argc >= 2) {
Expand Down
6 changes: 6 additions & 0 deletions examples/menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ void render(int rows, int cols, int menuheight, int menuwidth, int menupos) {

int main() {
try {
// check if the terminal is capable of handling input
if (!Term::is_stdin_a_tty()) {
std::cout << "The terminal is not attached to a TTY and therefore "
"can't catch user input. Exiting...\n";
return 1;
}
Terminal term(true, true, true, true);
int rows{}, cols{};
Term::get_term_size(rows, cols);
Expand Down
6 changes: 6 additions & 0 deletions examples/menu_window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ std::string render(Term::Window& scr,

int main() {
try {
// check if the terminal is capable of handling input
if (!Term::is_stdin_a_tty()) {
std::cout << "The terminal is not attached to a TTY and therefore "
"can't catch user input. Exiting...\n";
return 1;
}
Terminal term(true, true, true, true);
int rows{}, cols{};
Term::get_term_size(rows, cols);
Expand Down
6 changes: 6 additions & 0 deletions examples/menu_window_24bit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ std::string render(Term::Window_24bit& scr,

int main() {
try {
// check if the terminal is capable of handling input
if (!Term::is_stdin_a_tty()) {
std::cout << "The terminal is not attached to a TTY and therefore "
"can't catch user input. Exiting...\n";
return 1;
}
Terminal term(true, true, false, false);
int rows{}, cols{};
Term::get_term_size(rows, cols);
Expand Down
5 changes: 5 additions & 0 deletions examples/prompt_multiline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ bool determine_completeness([[maybe_unused]] std::string command) {

int main() {
try {
if (!Term::is_stdin_a_tty()) {
std::cout << "The terminal is not attached to a TTY and therefore "
"can't catch user input. Exiting...\n";
return 1;
}
Terminal term(false, true, false, false);
std::cout << "Interactive prompt." << std::endl;
std::cout << " * Use Ctrl-D to exit." << std::endl;
Expand Down
6 changes: 6 additions & 0 deletions examples/read_stdin.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <cpp-terminal/input.hpp>
#include <iostream>

int main() {
std::cout << "Input from stdin: " << Term::read_stdin_alone() << std::endl;
}