Compare commits

..

10 Commits

Author SHA1 Message Date
osamu-kj
fcf6a47a12 Vis: Update README.md 2023-05-20 02:33:06 +02:00
osamu-kj
2fbe8958d9 Shortcuts: Add copy-paste shortcuts 2023-05-20 02:31:33 +02:00
osamu-kj
15f8c9534f Vis: Remove unnecessary code + Update README.md 2023-05-20 02:08:12 +02:00
osamu-kj
17a621b787 General: Add many small fixes 2023-05-14 15:05:08 +02:00
osamu-kj
417f9fcbf2 CMake: Add necessary install rules for 'make install' 2023-05-14 14:22:27 +02:00
osamu-kj
87bb21be58 Calendar: Implement basic writing feature
In this commit several features were added as well.
Basic writing feature to a file. Added base64 decoding
to the reading feature. Checks whether or not the terminal
is too small. Basic help page.
2023-05-13 21:30:01 +02:00
osamu-kj
ce025500ec User Input: Fix small issue with the 'k' shortcut 2023-05-13 16:01:44 +02:00
osamu-kj
ad50383d03 Calendar: Implement basic reading feature
This commit contains a lot of different changes.
Starting from some refacting of user input code,
coloring, and adding a basic reading feature to
the program.
2023-05-13 15:58:02 +02:00
osamu-kj
f810759f12 Vis: Color days with events inside the Calendar
This commit presents two changes. Although the primary
being the functionality, that now days with events will
be colored. The second change is a new shortcut to quickly
delete events (x key).
2023-05-10 00:39:42 +02:00
osamu-kj
7da86f4645 Update README.md 2023-05-07 18:43:19 +02:00
15 changed files with 697 additions and 168 deletions

View File

@ -18,11 +18,15 @@ endif()
project(vis project(vis
VERSION 1.0 VERSION 1.0
DESCRIPTION "Vi Scheduler (vis) is a simple TUI program built for managing your schedules in a calendar-like grid." DESCRIPTION "Vi Scheduler (vis) is a simple TUI program built for managing your schedules in a calendar-like grid."
LANGUAGES CXX) LANGUAGES CXX C)
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
add_subdirectory(src) add_subdirectory(src)
find_library(NCURSES_LIB NAMES ncurses) find_library(NCURSES_LIB NAMES ncurses)
target_link_libraries(vis ncurses) target_link_libraries(vis ncurses)
install(TARGETS vis DESTINATION bin)

View File

@ -2,55 +2,58 @@
Vi Scheduler (VIS) is a lightweight tool that brings a Vim-like calendar to your terminal. It allows you to quickly view and edit your schedule, appointments, and tasks without leaving your command-line interface. Vi Scheduler (VIS) is a lightweight tool that brings a Vim-like calendar to your terminal. It allows you to quickly view and edit your schedule, appointments, and tasks without leaving your command-line interface.
Built using C++ and the Ncurses library, Vis offers a fast and efficient way to manage your time in the terminal. It suppors various navigation and editing commands inspired by Vim, such as navigating between days or months, adding and deleting events, and setting reminders. Built using C++ and the Ncurses library, vis offers a fast and efficient way to manage your time in the terminal. It suppors various navigation and editing commands inspired by Vim, such as navigating between days or months, adding and deleting events.
# Features ![Vi Scheduler - Preview](./preview/preview.png)
- Vim-like navigation and editing commands
- Multiple view modes: month, week
# Dependencies # Dependencies
The following is a list of dependencies that your system needs in order to be able to run Vis. The following is a list of dependencies that your system needs in order to be able to run vis.
- [The Ncurses library](https://invisible-island.net/ncurses/announce.html) - [The Ncurses library](https://invisible-island.net/ncurses/announce.html)
- [Moreutils](https://joeyh.name/code/moreutils/) - [Moreutils](https://joeyh.name/code/moreutils/)
# Building # Building & Installation
To build Vis, simply clone this repository and run `mkdir build; cd build; cmake ..; make` To build vis, simply clone this repository and run `mkdir build; cd build; cmake ..; make`
Resulting binary will be generated inside the `/build/src/` folder called. Resulting binary will be generated inside the `/build/src/` folder called.
For installation, you can run `sudo make install` (from the /build directory)
# Usage # Usage
To start Vis simply run the `vis` binary in your terminal alongside the name of the calendar file. To start vis simply run the `vis` binary in your terminal alongside the name of the calendar file.
For example: `vis school.cal` For example: `vis school.cal`
This will open the default view mode (month) and display the current month's calendar. From there, you can use the following commands to navigate and edit the calendar: This will open the default view mode (month) and display the current month's calendar. From there, you can use the following commands to navigate and edit the calendar:
- `h/j/k/l` - Move 1 day left/down/up/right - `h/j/k/l` - Move 1 day left/down/up/right
- `u/o` - Move 1 month left/right - `u/o` - Move 1 month left/right
- `gg` - Go to the beginning of the month - `g` - Go to the beginning of the month
- `G` - Go to the end of the month - `G` - Go to the end of the month
- `i` - Enter insert mode for the active day. - `i` - Enter insert mode for selected day.
- `x` - Delete event from selected day.
- `y` - Copy event
- `p` - Paste event
- `w` - Write changes to file (i.e. save)
- `q` - Quit and save the calendar - `q` - Quit and save the calendar
# Todos # Todos
The following is a list of things that have been/still have to be completed. The following is a list of things that have been/still have to be completed.
- Basic prototype with vipe (in memory only) - ~~Basic prototype with vipe (in memory only)~~
- Finish all the basic shortcuts - ~~Finish all the basic shortcuts~~
- Ability to write a calendar to a file - ~~Ability to write a calendar to a file~~
- Ability to read a calendar from a file - ~~Ability to read a calendar from a file~~
- Alerting function for errors and issues - Alerting function for errors and issues
- Logging / Debug flag - Logging / Debug flag
- Read input from stdin - Read input from stdin
- Set reminders - ~~Shortcut: ability to clone an event into another day~~
# Contributions # Contributions
Contributions and feedback are welcome! If you have any ideas or suggestions for improving Vis, please submit a pull request or open an issue on Github. Let's make the FOSS community better, together! Contributions and feedback are welcome! If you have any ideas or suggestions for improving vis, please submit a pull request or open an issue on Github. Let's make the FOSS community better, together!
# License # License

BIN
preview/preview.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -1,7 +1,12 @@
add_subdirectory(engine) add_subdirectory(engine)
add_subdirectory(calendar) add_subdirectory(calendar)
add_subdirectory(base64)
add_executable(vis main.cpp) add_executable(vis main.cpp)
target_link_libraries(vis engine) target_link_libraries(vis engine)
target_link_libraries(vis calendar) target_link_libraries(vis calendar)
target_link_libraries(vis base64)
set(installable_libs engine calendar base64)
install(TARGETS ${installable_libs} DESTINATION lib)

View File

@ -0,0 +1,2 @@
add_library(base64 SHARED base64.c)
install(FILES base64.h DESTINATION include)

209
src/base64/base64.c Normal file
View File

@ -0,0 +1,209 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/* ====================================================================
* Copyright (c) 1995-1999 The Apache Group. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* 4. The names "Apache Server" and "Apache Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Group and was originally based
* on public domain software written at the National Center for
* Supercomputing Applications, University of Illinois, Urbana-Champaign.
* For more information on the Apache Group and the Apache HTTP server
* project, please see <http://www.apache.org/>.
*
*/
/* Base64 encoder/decoder. Originally Apache file ap_base64.c
*/
#include <string.h>
#include "base64.h"
/* aaaack but it's fast and const should make it shared text page. */
static const unsigned char pr2six[256] =
{
/* ASCII table */
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
};
int Base64decode_len(const char *bufcoded)
{
int nbytesdecoded;
register const unsigned char *bufin;
register int nprbytes;
bufin = (const unsigned char *) bufcoded;
while (pr2six[*(bufin++)] <= 63);
nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
nbytesdecoded = ((nprbytes + 3) / 4) * 3;
return nbytesdecoded + 1;
}
int Base64decode(char *bufplain, const char *bufcoded)
{
int nbytesdecoded;
register const unsigned char *bufin;
register unsigned char *bufout;
register int nprbytes;
bufin = (const unsigned char *) bufcoded;
while (pr2six[*(bufin++)] <= 63);
nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
nbytesdecoded = ((nprbytes + 3) / 4) * 3;
bufout = (unsigned char *) bufplain;
bufin = (const unsigned char *) bufcoded;
while (nprbytes > 4) {
*(bufout++) =
(unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
*(bufout++) =
(unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
*(bufout++) =
(unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
bufin += 4;
nprbytes -= 4;
}
/* Note: (nprbytes == 1) would be an error, so just ingore that case */
if (nprbytes > 1) {
*(bufout++) =
(unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
}
if (nprbytes > 2) {
*(bufout++) =
(unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
}
if (nprbytes > 3) {
*(bufout++) =
(unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
}
*(bufout++) = '\0';
nbytesdecoded -= (4 - nprbytes) & 3;
return nbytesdecoded;
}
static const char basis_64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int Base64encode_len(int len)
{
return ((len + 2) / 3 * 4) + 1;
}
int Base64encode(char *encoded, const char *string, int len)
{
int i;
char *p;
p = encoded;
for (i = 0; i < len - 2; i += 3) {
*p++ = basis_64[(string[i] >> 2) & 0x3F];
*p++ = basis_64[((string[i] & 0x3) << 4) |
((int) (string[i + 1] & 0xF0) >> 4)];
*p++ = basis_64[((string[i + 1] & 0xF) << 2) |
((int) (string[i + 2] & 0xC0) >> 6)];
*p++ = basis_64[string[i + 2] & 0x3F];
}
if (i < len) {
*p++ = basis_64[(string[i] >> 2) & 0x3F];
if (i == (len - 1)) {
*p++ = basis_64[((string[i] & 0x3) << 4)];
*p++ = '=';
}
else {
*p++ = basis_64[((string[i] & 0x3) << 4) |
((int) (string[i + 1] & 0xF0) >> 4)];
*p++ = basis_64[((string[i + 1] & 0xF) << 2)];
}
*p++ = '=';
}
*p++ = '\0';
return p - encoded;
}

101
src/base64/base64.h Normal file
View File

@ -0,0 +1,101 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/* ====================================================================
* Copyright (c) 1995-1999 The Apache Group. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* 4. The names "Apache Server" and "Apache Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Group and was originally based
* on public domain software written at the National Center for
* Supercomputing Applications, University of Illinois, Urbana-Champaign.
* For more information on the Apache Group and the Apache HTTP server
* project, please see <http://www.apache.org/>.
*
*/
#ifndef _BASE64_H_
#define _BASE64_H_
#ifdef __cplusplus
extern "C" {
#endif
int Base64encode_len(int len);
int Base64encode(char * coded_dst, const char *plain_src,int len_plain_src);
int Base64decode_len(const char * coded_src);
int Base64decode(char * plain_dst, const char *coded_src);
#ifdef __cplusplus
}
#endif
#endif //_BASE64_H_

View File

@ -1 +1,2 @@
add_library(calendar SHARED calendar.cpp) add_library(calendar SHARED calendar.cpp)
install(FILES calendar.hpp DESTINATION include)

View File

@ -11,6 +11,13 @@ calendar_information::calendar_information() {
current_month_days = Calendar::get_days_in_month(current_month, current_year); current_month_days = Calendar::get_days_in_month(current_month, current_year);
} }
calendar_information::calendar_information(int cday, int cmonth, int cyear) {
current_day = cday;
current_month = cmonth;
current_year = cyear;
current_month_days = Calendar::get_days_in_month(current_month, current_year);
}
int Calendar::get_days_in_month(int month, int year) { int Calendar::get_days_in_month(int month, int year) {
tm date = {0}; tm date = {0};
date.tm_year = year - 1900; date.tm_year = year - 1900;
@ -45,7 +52,12 @@ calendar_information Calendar::get_info() {
return this->info; return this->info;
} }
calendar_information Calendar::get_current_date() {
return this->current_date;
}
Calendar::Calendar(calendar_information *preinfo) { Calendar::Calendar(calendar_information *preinfo) {
this->current_date = calendar_information();
this->info = *preinfo; this->info = *preinfo;
if (preinfo != nullptr) if (preinfo != nullptr)
@ -53,3 +65,28 @@ Calendar::Calendar(calendar_information *preinfo) {
this->info = calendar_information(); this->info = calendar_information();
} }
// https://stackoverflow.com/questions/6054016/c-program-to-find-day-of-week-given-date
// RETURNS:
// Number of the given day in its week.
// Note: it starts with sunday being 0
int get_weekday(calendar_information *date_info) {
if (date_info == nullptr)
return 0;
int d = date_info->current_day;
int m = date_info->current_month;
int y = date_info->current_year;
return (d += m < 3 ? y-- : y - 2, 23*m/9 + d + 4 + y/4- y/100 + y/400)%7;
}
int datecmp(calendar_information *one, calendar_information *two) {
if (one->current_day != two->current_day) return 0;
if (one->current_month != two->current_month) return 0;
if (one->current_month_days != two->current_month_days) return 0;
if (one->current_year != two->current_year) return 0;
return 1;
}

View File

@ -10,6 +10,7 @@ struct calendar_information {
int current_year; int current_year;
calendar_information(); calendar_information();
calendar_information(int cday, int cmonth, int cyear);
}; };
const bool operator<(const calendar_information& first, const calendar_information& second) { const bool operator<(const calendar_information& first, const calendar_information& second) {
@ -23,11 +24,17 @@ class Calendar {
void set_day(int day); void set_day(int day);
void set_month(int month); void set_month(int month);
void set_year(int year); void set_year(int year);
calendar_information get_info();
calendar_information get_info();
calendar_information get_current_date();
Calendar(calendar_information *preinfo = nullptr); Calendar(calendar_information *preinfo = nullptr);
private: private:
calendar_information info; calendar_information info; // mutable date that can be changed
calendar_information current_date; // current date
}; };
int get_weekday(calendar_information *date_info = nullptr);
int datecmp(calendar_information *one, calendar_information *two);
#endif #endif

View File

@ -1 +1,2 @@
add_library(engine SHARED engine.cpp) add_library(engine SHARED engine.cpp)
install(FILES engine.hpp DESTINATION include)

View File

@ -1,13 +1,12 @@
#include <stdlib.h> #include <stdlib.h>
#include <string>
#include <string.h> #include <string.h>
#include <ncurses.h> #include <ncurses.h>
#include <signal.h> #include <signal.h>
#include "engine.hpp" #include "engine.hpp"
Engine::Engine(int padding, calendar_view_mode view_mode) { Engine::Engine(int padding) {
this->padding = padding; this->padding = padding;
this->view_mode = view_mode;
this->cells_table = std::vector<engine_child>();
calendar_information date_info = calendar_information(); calendar_information date_info = calendar_information();
this->calendar = new Calendar(&date_info); this->calendar = new Calendar(&date_info);
@ -19,31 +18,34 @@ Engine::~Engine() {
} }
void Engine::ui_draw(WINDOW *win) { void Engine::ui_draw(WINDOW *win) {
this->cells_table.clear(); int screen_width, screen_height;
getmaxyx(win, screen_height, screen_width);
if (screen_height < 25 || screen_width < 70) {
this->ui_warning_draw(win, "Window resolution too small, please resize it.");
return;
}
low_res_flag = 0;
box(win, 0, 0); box(win, 0, 0);
wrefresh(win);
keypad(win, TRUE); keypad(win, TRUE);
keypad(stdscr, TRUE); keypad(stdscr, TRUE);
switch (this->view_mode) {
case MONTH_VIEW:
this->ui_month_draw(win); this->ui_month_draw(win);
break;
case WEEK_VIEW:
this->ui_week_draw(win);
break;
case MONTHS_VIEW:
this->ui_months_draw(win);
break;
}
this->ui_top_draw(win); this->ui_top_draw(win);
this->ui_bottom_draw(win); this->ui_bottom_draw(win);
wrefresh(win); wrefresh(win);
} }
void Engine::ui_warning_draw(WINDOW *win, const char *message) {
low_res_flag = 1;
mvwprintw(win, 0, 0, "%s", message);
wrefresh(win);
}
void Engine::ui_month_draw(WINDOW *win) { void Engine::ui_month_draw(WINDOW *win) {
calendar_information date_info = this->calendar->get_info(); calendar_information date_info = this->calendar->get_info();
int z = COLS - this->padding; int z = COLS - this->padding;
@ -52,25 +54,35 @@ void Engine::ui_month_draw(WINDOW *win) {
int x_location = this->padding + ((z/7) * (i%7)); int x_location = this->padding + ((z/7) * (i%7));
int y_location = this->padding + (q/(date_info.current_month_days/7) * (i/7)); int y_location = this->padding + (q/(date_info.current_month_days/7) * (i/7));
if (this->active_cell == i) wattron(win, COLOR_PAIR(1)); // check if day has an event
mvwprintw(win, y_location, x_location, "D%d", i+1); // TODO: Temporary solution
if (this->active_cell == i) wattroff(win, COLOR_PAIR(1)); calendar_information tmp_date = date_info;
tmp_date.current_day = i+1;
if (this->events_map.count(tmp_date) > 0)
wattron(win, COLOR_PAIR(2));
calendar_information current_date = this->calendar->get_current_date();
if (datecmp(&current_date, &tmp_date))
wattron(win, COLOR_PAIR(3));
if (this->active_cell == i)
wattron(win, COLOR_PAIR(1));
std::string weekday_prefix = weekday_prefixes[get_weekday(&tmp_date)];
// mvwprintw(win, y_location, x_location, "D%d", i+1);
mvwprintw(win, y_location, x_location, "%s[%d]", weekday_prefix.c_str(), i+1);
wattroff(win, COLOR_PAIR(1));
wattroff(win, COLOR_PAIR(2));
wattroff(win, COLOR_PAIR(3));
} }
} }
void Engine::ui_week_draw(WINDOW *win) {
}
void Engine::ui_months_draw(WINDOW *win) {
}
void Engine::ui_top_draw(WINDOW *win) { void Engine::ui_top_draw(WINDOW *win) {
if (VIS_COLORING) wattron(win, COLOR_PAIR(1)); if (VIS_COLORING) wattron(win, COLOR_PAIR(1));
mvwprintw(win, 1, 1, "Vi Scheduler"); mvwprintw(win, 1, 1, "Vi Scheduler");
mvwprintw(win, 2, 1, "@0xdeadbeer");
if (VIS_COLORING) wattroff(win, COLOR_PAIR(1)); if (VIS_COLORING) wattroff(win, COLOR_PAIR(1));
} }
@ -79,71 +91,29 @@ void Engine::ui_bottom_draw(WINDOW *win) {
if (VIS_COLORING) wattron(win, COLOR_PAIR(1)); if (VIS_COLORING) wattron(win, COLOR_PAIR(1));
calendar_information date_info = this->calendar->get_info(); calendar_information date_info = this->calendar->get_info();
std::string current_view_mode = calendar_view_mode_str[this->view_mode];
mvwprintw(win, LINES-2, 1, "Year: %d, Month: %d, Day: %d, Mode: %s\n", date_info.current_year, date_info.current_month, date_info.current_day, current_view_mode.c_str()); mvwprintw(win, LINES-2, 1, "Year: %d, Month: %d, Day: %d\n", date_info.current_year, date_info.current_month, date_info.current_day);
if (VIS_COLORING) wattroff(win, COLOR_PAIR(1)); if (VIS_COLORING) wattroff(win, COLOR_PAIR(1));
} }
void Engine::input_handle_month(WINDOW *win) { void Engine::input_handle(WINDOW *win) {
char key = getch(); char key = getch();
calendar_information date_info = this->calendar->get_info(); if (key == ERR) return;
if (low_res_flag) return;
int day, month, res; if (this->input_handle_universal(win, key))
return;
this->input_handle_month(win, key);
}
bool Engine::input_handle_universal(WINDOW *win, char key) {
int day;
switch (key) { switch (key) {
case 'h': case 'i': { // TODO: Break down this monstrocity of a case
if (this->calendar->get_info().current_day <= 1) break; endwin();
day = this->calendar->get_info().current_day;
this->calendar->set_day(--day);
--this->active_cell;
break;
case 'l':
if (this->calendar->get_info().current_day >= this->calendar->get_info().current_month_days) break;
day = this->calendar->get_info().current_day;
this->calendar->set_day(++day);
++this->active_cell;
break;
case 'j':
if (this->calendar->get_info().current_day+7 > this->calendar->get_info().current_month_days) break;
day = this->calendar->get_info().current_day;
this->calendar->set_day(day+7);
this->active_cell += 7;
break;
case 'k':
if (this->calendar->get_info().current_day-7 < 1) break;
day = this->calendar->get_info().current_day;
this->calendar->set_day(day-7);
this->active_cell -= 7;
break;
case 'u':
if (this->calendar->get_info().current_month <= 1) break;
month = this->calendar->get_info().current_month;
this->calendar->set_month(--month);
this->calendar->set_day(1);
this->active_cell = 0;
break;
case 'o':
if (this->calendar->get_info().current_month >= 12) break;
month = this->calendar->get_info().current_month;
this->calendar->set_month(++month);
this->calendar->set_day(1);
this->active_cell = 0;
break;
case 'i': {
int vipe_out[2], vipe_in[2]; int vipe_out[2], vipe_in[2];
char output_buffer[4096]; char output_buffer[4096];
memset(output_buffer, 0, sizeof(output_buffer)); memset(output_buffer, 0, sizeof(output_buffer));
@ -172,12 +142,102 @@ void Engine::input_handle_month(WINDOW *win) {
close(vipe_in[1]); close(vipe_in[1]);
int nbytes = read(vipe_out[0], output_buffer, sizeof(output_buffer)); int nbytes = read(vipe_out[0], output_buffer, sizeof(output_buffer));
if (nbytes > 0)
this->events_map[this->calendar->get_info()] = output_buffer; this->events_map[this->calendar->get_info()] = output_buffer;
else
this->events_map.erase(this->calendar->get_info());
} }
endwin(); wclear(win);
wrefresh(win);
break; break;
} }
case 'x': {
calendar_information date_info = this->calendar->get_info();
this->events_map.erase(date_info);
break;
}
case 'w':
this->write_calendar();
break;
case 'q':
endwin();
this->calendar_file.close();
exit(EXIT_SUCCESS);
break;
case 'y':
this->clipboard_day = this->calendar->get_info();
break;
case 'p':
if (this->events_map.find(this->clipboard_day) == this->events_map.end())
break;
this->events_map[this->calendar->get_info()] = this->events_map[this->clipboard_day];
break;
default:
return false;
break;
}
return true;
}
void Engine::input_handle_month(WINDOW *win, char key) {
calendar_information date_info = this->calendar->get_info();
int day, month;
switch (key) {
case 'h':
if (this->calendar->get_info().current_day <= 1) break;
day = this->calendar->get_info().current_day;
this->calendar->set_day(--day);
--this->active_cell;
break;
case 'l':
if (this->calendar->get_info().current_day >= this->calendar->get_info().current_month_days) break;
day = this->calendar->get_info().current_day;
this->calendar->set_day(++day);
++this->active_cell;
break;
case 'j':
if (this->calendar->get_info().current_day+7 > this->calendar->get_info().current_month_days) break;
day = this->calendar->get_info().current_day;
this->calendar->set_day(day+7);
this->active_cell += 7;
break;
case 'k':
if (this->calendar->get_info().current_day-7 < 1) break;
day = this->calendar->get_info().current_day;
this->calendar->set_day(day-7);
this->active_cell -= 7;
break;
case 'u':
if (this->calendar->get_info().current_month <= 1) break;
month = this->calendar->get_info().current_month;
this->calendar->set_month(--month);
this->calendar->set_day(1);
this->active_cell = 0;
break;
case 'o':
if (this->calendar->get_info().current_month >= 12) break;
month = this->calendar->get_info().current_month;
this->calendar->set_month(++month);
this->calendar->set_day(1);
this->active_cell = 0;
break;
case 'g': case 'g':
this->calendar->set_day(1); this->calendar->set_day(1);
this->active_cell = 0; this->active_cell = 0;
@ -186,17 +246,92 @@ void Engine::input_handle_month(WINDOW *win) {
this->calendar->set_day(this->calendar->get_info().current_month_days); this->calendar->set_day(this->calendar->get_info().current_month_days);
this->active_cell = this->calendar->get_info().current_month_days-1; this->active_cell = this->calendar->get_info().current_month_days-1;
break; break;
case 't':
this->view_mode = WEEK_VIEW;
wclear(win);
break;
} }
} }
void Engine::input_handle_week(WINDOW *win) { calendar_information Engine::parse_date(std::string date) {
char *token = strtok((char *) date.c_str(), ".");
std::vector<int> tokens;
while (token != NULL) {
try {
tokens.push_back(std::stoi(token));
} catch (...) {
std::cout << "Error parsing calendar file. Suspected incorrect format." << std::endl;
exit(EXIT_FAILURE);
}
token = strtok(NULL, ".");
}
return calendar_information(tokens[0], tokens[1], tokens[2]);
} }
void Engine::input_handle_months(WINDOW *win) { void Engine::parse_line(std::string line) {
// TODO char *token = strtok((char *) line.c_str(), " ");
std::vector<std::string> tokens;
while (token != NULL) {
tokens.push_back(token);
token = strtok(NULL, " ");
}
if (tokens.size() != 2)
return;
// decode the event from base64 before adding it into the events_map
calendar_information event_date = this->parse_date(tokens[0]);
int decoded_length = Base64decode_len((const char *) tokens[1].c_str());
char *event_decoded = (char *) malloc(decoded_length);
Base64decode(event_decoded, tokens[1].c_str());
this->events_map[event_date] = event_decoded;
free(event_decoded);
}
void Engine::open_calendar(char *filename) {
this->calendar_file.open(filename, std::ios::in);
this->calendar_file_location = filename;
// If the file does not exist,
// we'll create and reopen it later ('write' shortcut)
if (this->calendar_file.fail())
return;
std::string line;
while (std::getline(this->calendar_file, line))
this->parse_line(line);
}
bool Engine::write_calendar() {
this->calendar_file.close();
this->calendar_file.open(this->calendar_file_location, std::ios::out | std::ios::trunc);
if (this->calendar_file.fail()) {
mvprintw(0, 0, "Error saving file.");
refresh();
getch();
return false;
}
for (auto const& event : this->events_map) {
std::stringstream output_line;
calendar_information date = event.first;
int encoded_length = Base64encode_len(event.second.length());
char *event_encoded = (char *) malloc(encoded_length);
Base64encode(event_encoded, event.second.c_str(), event.second.length());
output_line << date.current_day << ".";
output_line << date.current_month << ".";
output_line << date.current_year << " ";
output_line << event_encoded;
this->calendar_file << output_line.str() << std::endl;
free(event_encoded);
}
return true;
} }

View File

@ -2,59 +2,58 @@
#define ENGINE_HPP #define ENGINE_HPP
#include <iostream> #include <iostream>
#include <sstream>
#include <fstream>
#include <ncurses.h> #include <ncurses.h>
#include <vector> #include <vector>
// #include <unordered_map>
#include <map> #include <map>
#include "../base64/base64.h"
#include "../calendar/calendar.hpp" #include "../calendar/calendar.hpp"
#include "../global/global.hpp" #include "../global/global.hpp"
struct engine_child { std::string weekday_prefixes[] = {
int x; "Sun",
int y; "Mon",
}; "Tue",
"Wed",
enum calendar_view_mode { "Thu",
MONTH_VIEW = 0, "Fri",
WEEK_VIEW, "Sat"
MONTHS_VIEW
};
std::string calendar_view_mode_str[] = {
"MONTH_VIEW",
"WEEK_VIEW",
"MONTHS_VIEW"
}; };
// title: drawing engine // title: drawing engine
// description: use for drawing the TUI and interact with the cells // description: use for drawing the TUI and interact with the cells
class Engine { class Engine {
public: public:
Engine(int padding = 10, calendar_view_mode view_mode = MONTH_VIEW); Engine(int padding);
~Engine(); ~Engine();
void ui_draw(WINDOW *win); void ui_draw(WINDOW *win);
void ui_warning_draw(WINDOW *win, const char *message);
void ui_month_draw(WINDOW *win); void ui_month_draw(WINDOW *win);
void ui_week_draw(WINDOW *win);
void ui_months_draw(WINDOW *win);
void ui_bottom_draw(WINDOW *win); void ui_bottom_draw(WINDOW *win);
void ui_top_draw(WINDOW *win); void ui_top_draw(WINDOW *win);
void input_handle_month(WINDOW *win); bool input_block;
void input_handle_week(WINDOW *win); void input_handle(WINDOW* win);
void input_handle_months(WINDOW *win); bool input_handle_universal(WINDOW *win, char key);
void input_handle_month(WINDOW *win, char key);
calendar_information parse_date(std::string date);
void parse_line(std::string line);
void open_calendar(char *filename);
bool write_calendar();
Calendar *calendar; Calendar *calendar;
// std::unordered_map<calendar_information, std::string> events_map;
std::map<calendar_information, std::string> events_map; std::map<calendar_information, std::string> events_map;
int active_cell; int active_cell;
calendar_view_mode view_mode; int padding; // GUI padding
int padding; // padding
private: private:
std::vector<engine_child> cells_table; std::fstream calendar_file;
char *calendar_file_location;
calendar_information clipboard_day;
}; };
#endif #endif

View File

@ -1,8 +1,11 @@
#ifndef VIS_GLOBAL #ifndef VIS_GLOBAL
#define VIS_GLOBAL #define VIS_GLOBAL
#include <signal.h>
#include <ncurses.h> #include <ncurses.h>
#define VIS_COLORING has_colors() && can_change_color() #define VIS_COLORING has_colors() && can_change_color()
volatile sig_atomic_t winch_flag = 0; // DESCRIPTION: flags if the resolution of the terminal has changed
volatile sig_atomic_t low_res_flag = 0; // DESCRIPTION: flags if the resolution of the terminal is too small
#endif #endif

View File

@ -6,36 +6,51 @@
#include "engine/engine.hpp" #include "engine/engine.hpp"
#include "global/global.hpp" #include "global/global.hpp"
Engine engine = Engine(10, MONTH_VIEW); Engine engine(10);
WINDOW *main_win; WINDOW *main_win;
void sig_winch(int sig) { void sig_winch(int sig) {
if (isendwin()) return; winch_flag = 1;
endwin();
wclear(main_win);
wrefresh(main_win);
wresize(main_win, LINES, COLS);
mvwin(main_win, 0, 0);
// redraw the TUI after the resize signal
engine.ui_draw(main_win);
flushinp();
return;
} }
void signals() { void signals() {
signal(SIGWINCH, sig_winch); signal(SIGWINCH, sig_winch);
} }
int main() { void print_help() {
std::cout << "\
VIS - Vim Scheduler\
\n\
\nUsage: vis [file]\
\n\
\nModes: \
\n - Month view (default): view the current month\
\n - Week view: view the current week\
\n - Months view: view the current year\
" << std::endl;
}
bool check_args(int argc, char **argv) {
if (argc != 2) {
print_help();
return false;
}
engine.open_calendar(argv[1]);
return true;
}
int main(int argc, char **argv) {
if (!check_args(argc, argv))
return EXIT_FAILURE;
initscr(); initscr();
refresh(); refresh();
curs_set(0); // invisible cursor curs_set(0); // invisible cursor
noecho();
halfdelay(1);
refresh(); refresh();
main_win = newwin(LINES, COLS, 0, 0); main_win = newwin(LINES, COLS, 0, 0);
@ -48,22 +63,29 @@ int main() {
init_pair(0, COLOR_WHITE, COLOR_BLACK); init_pair(0, COLOR_WHITE, COLOR_BLACK);
init_pair(1, COLOR_BLACK, COLOR_WHITE); init_pair(1, COLOR_BLACK, COLOR_WHITE);
init_pair(2, COLOR_BLACK, COLOR_RED);
init_pair(3, COLOR_BLACK, COLOR_GREEN);
} }
// handle required signals // handle required signals
signals(); signals();
for (;;) { for (;;) {
engine.ui_draw(main_win); if (winch_flag) {
winch_flag = 0;
endwin();
wrefresh(main_win);
wclear(main_win);
if (engine.view_mode == MONTH_VIEW) wresize(main_win, LINES, COLS);
engine.input_handle_month(main_win); mvwin(main_win, 0, 0);
if (engine.view_mode == WEEK_VIEW)
engine.input_handle_week(main_win);
else if (engine.view_mode == MONTHS_VIEW)
engine.input_handle_months(main_win);
} }
engine.ui_draw(main_win);
engine.input_handle(main_win);
}
endwin(); endwin();
return 0; return 0;