Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI: Simple ncurses window with ls-like output #11

Draft
wants to merge 24 commits into
base: master
Choose a base branch
from
Draft
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
14 changes: 9 additions & 5 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,37 @@ jobs:
# cross-platform coverage.
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
runs-on: ubuntu-latest
container: rikorose/gcc-cmake:latest

steps:
- uses: actions/checkout@v2

- name: Install dependencies
run: apt-get update && apt-get install -yq libboost-thread-dev libboost-system-dev

- name: Create Build Environment
# Some projects don't allow in-source building, so create a separate build directory
# We'll use this as our working directory for all subsequent commands
run: cmake -E make_directory ${{runner.workspace}}/build
run: cmake -E make_directory build

- name: Configure CMake
# Use a bash shell so we can use the same syntax for environment variable
# access regardless of the host operating system
shell: bash
working-directory: ${{runner.workspace}}/build
working-directory: build
# Note the current convention is to use the -S and -B options here to specify source
# and build directories, but this is only available with CMake 3.13 and higher.
# The CMake binaries on the Github Actions machines are (as of this writing) 3.12
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE
run: cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE

- name: Build
working-directory: ${{runner.workspace}}/build
working-directory: build
shell: bash
# Execute the build. You can specify a specific target with "--target <NAME>"
run: cmake --build . --config $BUILD_TYPE

- name: Test
working-directory: ${{runner.workspace}}/build
working-directory: build
shell: bash
# Execute tests defined by the CMake configuration.
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
Expand Down
38 changes: 38 additions & 0 deletions include/buffer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#ifndef __BUFFER_HPP
#define __BUFFER_HPP

#include <filesystem>
#include <string>
#include <vector>

namespace fs = std::filesystem;

namespace rang
{
class buffer
{
public:
std::vector<std::string> contents;

buffer() = default;

virtual ~buffer() = default;

virtual void update() = 0;
p4vook marked this conversation as resolved.
Show resolved Hide resolved
};

class dummy : buffer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class does not contain any logic, therefore it remains abstract, so we couldn't use it as "dummy" class.
Seems it needs to implement the stub update() method.

{
};

class directory_listing : public buffer
{
public:
fs::path directory;

directory_listing(fs::path _directory);

void update();
};
} // namespace rang
#endif
40 changes: 40 additions & 0 deletions include/evloop.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#ifndef __EVLOOP_HPP
#define __EVLOOP_HPP

#include <boost/asio.hpp>
#include <functional>
#include <string>
#include <vector>

#undef timeout

namespace rang
{
class event_loop
{
private:
boost::asio::io_context io_context;
boost::asio::signal_set signals;
boost::asio::posix::stream_descriptor input;

public:
event_loop();

template <class duration>
void add_regular_job(const std::function<void()> callback,
const duration &interval); // TODO implementation

template <class time_point>
void add_job(const std::function<void()> callback, time_point &time); // TODO implementation

void set_input_reaction(const std::function<void(int)> callback);

void run();

void stop();

private:
void handle_input(const std::function<void(int)> &callback);
};
} // namespace rang
#endif
6 changes: 0 additions & 6 deletions include/rang.h

This file was deleted.

25 changes: 25 additions & 0 deletions include/rwindow.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef __RWINDOW_HPP
#define __RWINDOW_HPP

#include "buffer.hpp"
#include "console_io.hpp"

namespace rang
{
class window
{
private:
console_io::window win;
buffer &tied_buf;

public:
int offset_x = 0, offset_y = 0;
window(console_io::window &&_win, buffer &_tied_buf);

void refresh();

void scroll_viewport(int shift);
};
} // namespace rang

#endif
9 changes: 7 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
add_executable (rang rang.cpp)
add_subdirectory(console_io)

add_executable (rang evloop.cpp buffer.cpp rwindow.cpp rang.cpp)

find_package(Boost 1.60.0 REQUIRED COMPONENTS system thread)

target_compile_features(rang PUBLIC cxx_std_17)
target_include_directories(rang PUBLIC ${CURSES_INCLUDE_DIRS})
target_link_libraries(rang PUBLIC ${CURSES_LIBRARIES})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that we should make a CMake module which will export the Curses imported target and use it (like
target_link_libraries(rang PUBLIC Curses::Curses). This approach is more clear and we could avoid the cumbersome adding of include_directories and libraries if we declare it as INTERFACE in our imported target: target_include_directories(Curses::Curses INTERFACE ${CURSES_INCLUDE_DIRS}).

target_link_libraries(rang PUBLIC ${CURSES_LIBRARIES} ${Boost_LIBRARIES} console_io)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also prefer the FindBoost's exported targets here: Boost::system Boost::thread.

31 changes: 31 additions & 0 deletions src/buffer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "buffer.hpp"
#include <algorithm>

using namespace rang;

directory_listing::directory_listing(fs::path _directory) : directory(_directory)
{
}

void directory_listing::update()
{
std::vector<fs::directory_entry> filtered;
fs::directory_iterator it(directory);
std::copy_if(fs::begin(it), fs::end(it), std::back_insert_iterator(filtered),
[](fs::directory_entry entry) -> bool {
return entry.path().filename().string().front() != '.';
});
std::sort(filtered.begin(), filtered.end(),
[](fs::directory_entry entry1, fs::directory_entry entry2) -> bool {
if (entry1.is_directory() != entry2.is_directory()) {
return entry1.is_directory();
}
return entry1.path().filename().string() <
entry2.path().filename().string();
});
contents.resize(filtered.size());
transform(filtered.begin(), filtered.end(), contents.begin(),
[](fs::directory_entry entry) -> std::string {
return entry.path().filename().string();
});
}
6 changes: 6 additions & 0 deletions src/console_io/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.17)
project(console_io)

add_library(console_io OBJECT src/window.cpp src/base.cpp)

target_include_directories(console_io PUBLIC include)
18 changes: 18 additions & 0 deletions src/console_io/include/base.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifndef __SCREEN_HPP
#define __SCREEN_HPP

#include "window.hpp"
#include <ncurses.h>

namespace console_io
{
class ncurses : public window
{
public:
ncurses();

~ncurses();
};
} // namespace console_io

#endif
7 changes: 7 additions & 0 deletions src/console_io/include/console_io.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#ifndef __CONSOLE_IO_HPP
#define __CONSOLE_IO_HPP
#include "base.hpp"
#include "window.hpp"

#undef timeout
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to add comment why this #undef directive is here or drop it, if it doesn't use.

#endif
53 changes: 53 additions & 0 deletions src/console_io/include/window.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#ifndef __WINDOW_HPP
#define __WINDOW_HPP

#include <memory>
#include <ncurses.h>
#include <string>
#include <vector>

namespace console_io
{
class window
{
protected:
WINDOW *win_ptr = nullptr;
int size_x = 0;
int size_y = 0;
int offset_x = 0;
int offset_y = 0;

public:
window *parent = nullptr;
std::vector<window> subwindows;

window() = default;

window(int _size_x, int _size_y, int _offset_x, int _offset_y, window *_parent = nullptr);

~window();

bool operator==(const window &other) const;

int get_size_x() const;
int get_size_y() const;
int get_offset_x() const;
int get_offset_y() const;

void refresh() const;

void move(int x, int y) const;

void output(std::string s) const;

void move_and_output(int x, int y, std::string s) const;

void outputln(int y, std::string s) const;

window subwindow(int _size_x, int _size_y, int offset_x, int offset_y);

int set_keypad(bool value) const;
};
} // namespace console_io

#endif
27 changes: 27 additions & 0 deletions src/console_io/src/base.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include "base.hpp"
#include <algorithm>

using namespace console_io;

ncurses::ncurses()
{
win_ptr = initscr();
if (win_ptr == nullptr) {
throw 1;
}
size_x = COLS;
size_y = LINES;
}

ncurses::~ncurses()
{
if (win_ptr == stdscr) { // guarantee Liskov substitution
endwin();
} else {
if (parent != nullptr) {
parent->subwindows.erase(
std::find(parent->subwindows.begin(), parent->subwindows.end(), *this));
}
delwin(win_ptr);
}
}
Loading