@ -0,0 +1 @@ | |||||
build/* |
@ -0,0 +1,34 @@ | |||||
CXX = clang++ | |||||
CXXFLAGS = --std=c++17 -O3 -Iinclude | |||||
USE_THREADS = -pthread | |||||
USE_FILESYSTEM = -lc++fs | |||||
USE_SDL = -lSDL2 | |||||
all: build | |||||
build: pomodoro unix | |||||
unix: yes | |||||
clean: clean_pomodoro | |||||
dirs: | |||||
@mkdir -p ./build/bin | |||||
pomodoro: dirs | |||||
$(CXX) $(CXXFLAGS) $(USE_SDL) $(USE_THREADS) src/pomodoro/pomodoro.cpp -o ./build/bin/pomodoro_view | |||||
clean_pomodoro: | |||||
-@rm ./build/bin/pomodoro_view | |||||
yes: dirs | |||||
$(CXX) $(CXXFLAGS) src/yes/yes.cpp -o ./build/bin/yes | |||||
yes_clean: | |||||
-@rm ./build/bin/yes | |||||
astyle: | |||||
astyle --style=bsd --align-reference=type --align-pointer=type --break-blocks --indent-namespaces --indent=tab --add-brackets \ | |||||
include/rigid_paradise/*.h \ | |||||
src/pomodoro/pomodoro.cpp \ | |||||
src/yes/yes.cpp \ |
@ -0,0 +1,3 @@ | |||||
pomodoro_sound ~/.rigidparadise/sound.wav | |||||
pomodoro.tasks ~/.rigidparadise/pomodoro.tasks | |||||
pomodoro.log ~/.rigidparadise/pomodoro.log |
@ -0,0 +1,47 @@ | |||||
#pragma once | |||||
#include <fstream> | |||||
#include <iostream> | |||||
#include <string> | |||||
#include <cctype> | |||||
#include <algorithm> | |||||
namespace config | |||||
{ | |||||
inline std::string get_value(const std::string& source) | |||||
{ | |||||
std::string ret = source; | |||||
try | |||||
{ | |||||
std::ifstream config_file("/home/archivist/.rigidparadise/rp.cfg"); | |||||
if(!config_file.good()) | |||||
{ | |||||
std::cerr << "Unable to read configuration"<<std::endl; | |||||
} | |||||
while(config_file.good()) | |||||
{ | |||||
std::string str; | |||||
getline (config_file, str); | |||||
if(str.size()>1 && str[0] != '#') | |||||
{ | |||||
auto end = std::find_if(str.begin(), str.end(), isspace); | |||||
size_t pos = end-str.begin(); | |||||
std::string_view name{str.data(), pos}; | |||||
if(name == source) | |||||
{ | |||||
ret = std::string{end+1, str.end()}; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
catch(...) | |||||
{} | |||||
return ret; | |||||
} | |||||
} |
@ -0,0 +1,68 @@ | |||||
#pragma once | |||||
#include <string> | |||||
#include <sstream> | |||||
#include <chrono> | |||||
#include <iostream> | |||||
namespace display | |||||
{ | |||||
inline std::string escape_csv(const std::string& value) | |||||
{ | |||||
std::stringstream ret; | |||||
ret<<"\""; | |||||
for(auto v : value) | |||||
{ | |||||
switch(v) | |||||
{ | |||||
case '\n': | |||||
ret << "\\n"; | |||||
break; | |||||
case '\t': | |||||
ret << "\\t"; | |||||
break; | |||||
case '"': | |||||
ret << "\\\""; | |||||
break; | |||||
default: | |||||
ret << v; | |||||
break; | |||||
} | |||||
} | |||||
ret<<"\""; | |||||
return ret.str(); | |||||
} | |||||
inline std::string to_string(std::chrono::seconds v) | |||||
{ | |||||
std::stringstream ret; | |||||
ret << v.count() << " second" << (v.count()!=1?"s":""); | |||||
return ret.str(); | |||||
} | |||||
inline std::string to_string(std::chrono::minutes v) | |||||
{ | |||||
std::stringstream ret; | |||||
ret << v.count() << " minute" << (v.count()!=1?"s":""); | |||||
return ret.str(); | |||||
} | |||||
inline void header(std::string app_name) | |||||
{ | |||||
std::cout << "\033[2J" << "\033[1;1H"; | |||||
std::cout << "Rigid Paradise's "<<app_name<<std::endl; | |||||
} | |||||
template<typename T> | |||||
void pair_set(const T& value) | |||||
{ | |||||
for(auto action : value) | |||||
{ | |||||
std::cout << " [" << action.first << "]: " << action.second<<std::endl; | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,40 @@ | |||||
#pragma once | |||||
#include <utility> | |||||
#include <set> | |||||
#include <fstream> | |||||
#include <rigid_paradise/config.h> | |||||
namespace pomodoro | |||||
{ | |||||
using pomotask = std::pair<int, std::string>; | |||||
std::set<pomotask> get_pomodoro_tasks() | |||||
{ | |||||
std::set<std::pair<int, std::string>> ret; | |||||
std::ifstream tasks(config::get_value("pomodoro.tasks")); | |||||
int counter = 1; | |||||
while(tasks.good()) | |||||
{ | |||||
std::string str; | |||||
getline (tasks, str); | |||||
if(str.size()>1 && str[0] != '#') | |||||
{ | |||||
ret.insert(std::make_pair(counter++, str)); | |||||
} | |||||
} | |||||
return ret; | |||||
} | |||||
} | |||||
#define pomodoro_actions_unwrap {\ | |||||
std::make_pair<char, std::string>('P',"Productive work"),\ | |||||
std::make_pair<char, std::string>('B',"Parallel work"),\ | |||||
std::make_pair<char, std::string>('C',"Non productive work"),\ | |||||
std::make_pair<char, std::string>('D',"Productive discution or chat"),\ | |||||
std::make_pair<char, std::string>('E',"Non productive chat"),\ | |||||
std::make_pair<char, std::string>('T',"Learning"),\ | |||||
std::make_pair<char, std::string>('S',"Improductive activity"),\ | |||||
std::make_pair<char, std::string>('Z',"Break")\ | |||||
} |
@ -0,0 +1,2 @@ | |||||
#pragma once | |||||
#include "rigid_paradise/systems/unix/stdio.h" |
@ -0,0 +1,31 @@ | |||||
#pragma once | |||||
#include <unistd.h> | |||||
#include <fcntl.h> | |||||
#include <stdint.h> | |||||
namespace os{ | |||||
constexpr auto write = [](int32_t fd, const char* ptr, int64_t size){ | |||||
do | |||||
{ | |||||
auto check = ::write(fd, ptr, size); | |||||
if(check<0) | |||||
{ | |||||
return check; | |||||
} | |||||
size-=check; | |||||
ptr+=check; | |||||
}while(size!=0); | |||||
return size; | |||||
}; | |||||
constexpr auto stdout_write = [](const char* ptr, size_t size){ | |||||
return write(0, ptr, size); | |||||
}; | |||||
constexpr auto stderr_write = [](const char* ptr, size_t size){ | |||||
return write(2, ptr, size); | |||||
}; | |||||
} |
@ -0,0 +1,255 @@ | |||||
#include <SDL2/SDL.h> | |||||
#ifdef SV_EXP | |||||
#include <experimental/string_view> | |||||
namespace std | |||||
{ | |||||
using string_view = std::experimental::string_view; | |||||
} | |||||
#else | |||||
#include <string_view> | |||||
#endif | |||||
#include <vector> | |||||
#include <set> | |||||
#include <chrono> | |||||
#include <thread> | |||||
#include <atomic> | |||||
#include <string> | |||||
#include <utility> | |||||
#include <iostream> | |||||
#include <sstream> | |||||
#include <cassert> | |||||
#include <random> | |||||
#include <fstream> | |||||
#include <algorithm> | |||||
#include "rigid_paradise/display.h" | |||||
#include "rigid_paradise/config.h" | |||||
#include "rigid_paradise/pomodoro.h" | |||||
using namespace std::chrono_literals; | |||||
auto wait_interval = 12min; | |||||
//auto wait_interval = 12s; | |||||
std::vector<std::string_view> audioDeviceNames; | |||||
std::vector<SDL_AudioDeviceID> audioDeviceIDs; | |||||
Uint8* audio_pos; // global pointer to the audio buffer to be played | |||||
Uint8* audio_pos_orig; // global pointer to the audio buffer to be played | |||||
Uint32 audio_len; // remaining length of the sample we have to play | |||||
Uint32 audio_len_orig; // remaining length of the sample we have to play | |||||
std::atomic<bool> must_play = false; | |||||
std::minstd_rand bad_rng; | |||||
std::set<std::pair<char, std::string>> pomodoro_actions = pomodoro_actions_unwrap; | |||||
namespace sound_mng | |||||
{ | |||||
void my_audio_callback(void* userdata, Uint8* stream, int len) | |||||
{ | |||||
if (audio_len ==0) | |||||
{ | |||||
return; | |||||
} | |||||
len = ( len > audio_len ? audio_len : len ); | |||||
//SDL_memcpy (stream, audio_pos, len); // simply copy from one buffer into the other | |||||
SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);// mix from one buffer into another | |||||
audio_pos += len; | |||||
audio_len -= len; | |||||
} | |||||
constexpr SDL_AudioSpec base_spec = | |||||
{ | |||||
.freq = 48000, | |||||
.format = AUDIO_F32, | |||||
.channels = 2, | |||||
.silence = 0, | |||||
.samples = 4096, | |||||
.callback = my_audio_callback, | |||||
.userdata = nullptr | |||||
}; | |||||
void loadAudioDevices() | |||||
{ | |||||
int i, count = SDL_GetNumAudioDevices(0); | |||||
for (i = 0; i < count; ++i) | |||||
{ | |||||
const char* name = SDL_GetAudioDeviceName(i, 0); | |||||
audioDeviceNames.push_back(name); | |||||
SDL_AudioSpec ignored; | |||||
audioDeviceIDs.push_back(SDL_OpenAudioDevice( | |||||
name, | |||||
0, | |||||
&base_spec, | |||||
&ignored, | |||||
0 | |||||
)); | |||||
} | |||||
} | |||||
void player() | |||||
{ | |||||
while ( true ) | |||||
{ | |||||
while(must_play) | |||||
{ | |||||
SDL_PauseAudio(0); | |||||
std::this_thread::sleep_for(1s); | |||||
audio_pos = audio_pos_orig; | |||||
audio_len = audio_len_orig; | |||||
SDL_PauseAudio(1); | |||||
std::this_thread::sleep_for(3s); | |||||
} | |||||
std::this_thread::sleep_for(1s); | |||||
} | |||||
return; | |||||
} | |||||
} | |||||
int main(); | |||||
int WinMain() | |||||
{ | |||||
return main(); | |||||
} | |||||
int main() | |||||
{ | |||||
assert(SDL_Init(SDL_INIT_AUDIO) >= 0); | |||||
sound_mng::loadAudioDevices(); | |||||
// sound data | |||||
static Uint32 wav_length; // length | |||||
static Uint8* wav_buffer; // buffer containing our audio file | |||||
static SDL_AudioSpec wav_spec; // the specs of our sound | |||||
// Load the WAV | |||||
assert( SDL_LoadWAV(config::get_value("pomodoro_sound").c_str(), &wav_spec, &wav_buffer, &wav_length) != NULL ); | |||||
// set the callback function | |||||
wav_spec.callback = sound_mng::my_audio_callback; | |||||
wav_spec.userdata = NULL; | |||||
// set our global static variables | |||||
audio_pos = wav_buffer; // copy sound buffer | |||||
audio_pos_orig = wav_buffer; // copy sound buffer | |||||
audio_len = wav_length; // copy file length | |||||
audio_len_orig = wav_length; // copy file length | |||||
/* Open the device */ | |||||
if ( SDL_OpenAudio(&wav_spec, NULL) < 0 ) | |||||
{ | |||||
fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError()); | |||||
exit(-1); | |||||
} | |||||
std::thread my_player{sound_mng::player}; | |||||
/********************* MAIN LOOP *************************/ | |||||
bool quit = false; | |||||
while(!quit) | |||||
{ | |||||
display::header("Pomodoro"); | |||||
std::cout << "> Interval time is: "<< display::to_string(wait_interval) <<std::endl; | |||||
std::cout << "> Tasklist excerpt:\n"; | |||||
std::array<pomodoro::pomotask,5> sample; | |||||
auto list = pomodoro::get_pomodoro_tasks(); | |||||
auto smp_end = std::sample(list.begin(), list.end(), sample.begin(),5, bad_rng); | |||||
for(auto it = sample.begin(); it != smp_end; it++) | |||||
{ | |||||
std::cout << "> ["<<it->first<<"]: "<<it->second<<"\n"; | |||||
} | |||||
std::cout<<std::endl; | |||||
std::this_thread::sleep_for(wait_interval); | |||||
must_play.store(true); | |||||
{ | |||||
display::header("Pomodoro"); | |||||
std::cout << "> Select your current action:" << std::endl; | |||||
display::pair_set(pomodoro_actions); | |||||
char action; | |||||
bool valid=false; | |||||
do | |||||
{ | |||||
std::string str; | |||||
getline (std::cin, str); | |||||
auto is_matching = [&](auto action) | |||||
{ | |||||
return str[0]==action.first; | |||||
}; | |||||
if( | |||||
std::any_of( | |||||
pomodoro_actions.begin(), | |||||
pomodoro_actions.end(), | |||||
is_matching | |||||
) | |||||
) | |||||
{ | |||||
action=str[0]; | |||||
valid=true; | |||||
} | |||||
} | |||||
while(!valid); | |||||
auto task_list = pomodoro::get_pomodoro_tasks(); | |||||
std::cout<<"> Select your current assigned task:"<<std::endl; | |||||
display::pair_set(task_list); | |||||
int task_nb; | |||||
std::string task_label; | |||||
valid=false; | |||||
do | |||||
{ | |||||
try | |||||
{ | |||||
std::cin >> task_nb; | |||||
} | |||||
catch(...) | |||||
{ | |||||
task_nb = 0; | |||||
} | |||||
std::for_each(task_list.begin(), task_list.end(), [&](auto action) | |||||
{ | |||||
if(task_nb==action.first) | |||||
{ | |||||
valid=true; | |||||
task_label = display::escape_csv(action.second); | |||||
} | |||||
}); | |||||
} | |||||
while(!valid); | |||||
std::ofstream(config::get_value("pomodoro.log"), std::ofstream::app)<<std::chrono::seconds(std::time(NULL)).count()<<"\t"<<action<<"\t"<<task_label<<std::endl; | |||||
} | |||||
must_play.store(false); | |||||
} | |||||
// shut everything down | |||||
SDL_CloseAudio(); | |||||
SDL_FreeWAV(wav_buffer); | |||||
} |
@ -0,0 +1,31 @@ | |||||
#ifdef SV_EXP | |||||
#include <experimental/string_view> | |||||
namespace std | |||||
{ | |||||
using string_view = std::experimental::string_view; | |||||
} | |||||
#else | |||||
#include <string_view> | |||||
#endif | |||||
#include <vector> | |||||
#include <set> | |||||
#include <chrono> | |||||
#include <thread> | |||||
#include <atomic> | |||||
#include <string> | |||||
#include <utility> | |||||
#include <iostream> | |||||
#include <sstream> | |||||
#include <cassert> | |||||
#include <random> | |||||
#include <fstream> | |||||
#include <algorithm> | |||||
#include "rigid_paradise/display.h" | |||||
#include "rigid_paradise/config.h" | |||||
#include "rigid_paradise/pomodoro.h" | |||||
using namespace std::chrono_literals; | |||||
std::set<std::pair<char, std::string>> pomodoro_actions = pomodoro_actions_unwrap; | |||||
@ -0,0 +1,67 @@ | |||||
#include <vector> | |||||
#include <algorithm> | |||||
#include <string> | |||||
#include <sstream> | |||||
#include <rigid_paradise/systems/stdio.h> | |||||
#include <string.h> | |||||
#ifndef EXIT_FAILURE | |||||
#define EXIT_FAILURE -1 | |||||
#endif | |||||
const char* help = | |||||
"RigidParadise Yes, no version number\n\ | |||||
Archivist - 2019\n\ | |||||
usage: yes [STRING]*\n\ | |||||
Repeatedly output a line with all specified STRING(s), or 'y'.\n\ | |||||
yes --help\n\ | |||||
yes --version\n\ | |||||
Display this text.\n"; | |||||
const size_t help_len = strlen(help); | |||||
int main(int argc, char** argv) | |||||
{ | |||||
std::string to_write = "y\n"; | |||||
std::vector<char> str; | |||||
constexpr size_t target_size = 1 << 15; | |||||
str.reserve(target_size); | |||||
if(argc>1) | |||||
{ | |||||
if(argv[1][0]=='-' && argv[1][1]=='-') | |||||
{ | |||||
os::stdout_write(help, help_len); | |||||
return 0; | |||||
} | |||||
std::stringstream generator; | |||||
std::for_each(argv+1, argv+argc, [&](auto cstring) | |||||
{ | |||||
generator << cstring << ' '; | |||||
}); | |||||
to_write = generator.str(); | |||||
to_write[to_write.size()-1]='\n'; | |||||
} | |||||
do | |||||
{ | |||||
for(auto a : to_write) | |||||
{ | |||||
str.push_back(a); | |||||
} | |||||
} | |||||
while(str.size()<(target_size)); | |||||
do | |||||
{ | |||||
auto check = os::stdout_write(str.data() , str.size()); | |||||
if(check<0) | |||||
{ | |||||
return EXIT_FAILURE; | |||||
} | |||||
} | |||||
while(1); | |||||
return 0; | |||||
} |