| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- /**
- * curseOutput.cpp for jsonstroller
- *
- * Author: isundil <isundill@gmail.com>
- **/
- #include <iostream>
- #include <sys/ioctl.h>
- #include <algorithm>
- #include <unistd.h>
- #include <signal.h>
- #include <string.h>
- #include "searchPattern.hh"
- #include "curseOutput.hh"
- #include "jsonPrimitive.hh"
- #include "jsonObject.hh"
- #include "jsonArray.hh"
- #include "except.hh"
- #include "streamConsumer.hh"
- static CurseOutput *runningInst = nullptr;
- CurseOutput::CurseOutput(const Params &p): params(p)
- {
- runningInst = this;
- }
- CurseOutput::~CurseOutput()
- {
- struct winsize size;
- runningInst = nullptr;
- if (ioctl(fileno(screen_fd ? screen_fd : stdout), TIOCGWINSZ, &size) == 0)
- resize_term(size.ws_row, size.ws_col);
- }
- void CurseOutput::loop(WINDOW * w)
- {
- inputResult read;
- breakLoop = false;
- do
- {
- while (!redraw());
- read = readInput(w);
- } while (read != inputResult::quit);
- }
- void CurseOutput::onResizeHandler()
- {
- clear();
- }
- bool CurseOutput::onsig(int signo)
- {
- struct winsize size;
- t_Cursor oldScrSize;
- switch (signo)
- {
- case SIGWINCH:
- if (ioctl(fileno(screen_fd ? screen_fd : stdout), TIOCGWINSZ, &size) == 0)
- resize_term(size.ws_row, size.ws_col);
- screenSize = getScreenSize();
- onResizeHandler();
- while (!redraw());
- break;
- case SIGCONT:
- oldScrSize = getScreenSizeUnsafe();
- if (ioctl(fileno(screen_fd ? screen_fd : stdout), TIOCGWINSZ, &size) == -1)
- break;
- if (size.ws_row != oldScrSize.second || size.ws_col != oldScrSize.first)
- kill(getpid(), SIGWINCH);
- break;
- case SIGKILL:
- case SIGINT:
- case SIGTERM:
- breakLoop = true;
- break;
- default:
- return false;
- }
- return true;
- }
- void _resizeFnc(int signo)
- {
- if (runningInst)
- runningInst->onsig(signo);
- signal(signo, _resizeFnc);
- }
- /**
- * Read input and expect signal
- * @Return true on:
- * - Windows resized
- * - Key press and need redraw
- * false on:
- * - exit signal
- **/
- inputResult CurseOutput::readInput(WINDOW *w)
- {
- while (!breakLoop)
- {
- inputResult r = evalKey(InputSequence::read(w));
- if (r != inputResult::nextInput)
- return r;
- }
- return inputResult::quit;
- }
- inputResult CurseOutput::evalKey(const InputSequence &c)
- {
- const std::string key = c.key();
- if (key == "Q")
- return inputResult::quit;
- else if (key == "K" || key == "KEY_UP")
- return selectUp();
- else if (key == "J" || key == "KEY_DOWN")
- return selectDown();
- else if (key == "KEY_PPAGE")
- return selectPUp();
- else if (key == "KEY_NPAGE")
- return selectPDown();
- else if (key == "L" || key == "KEY_RIGHT")
- return expandSelection();
- else if (key == "H" || key == "KEY_LEFT")
- return collapseSelection();
- else if (key == "/")
- return initSearch();
- else if (key == "N")
- return nextResult();
- else if (key == "^W-W")
- return changeWindow(1, true);
- else if (key == "^W-KEY_RIGHT" || key == "^W-L")
- return changeWindow(1, false);
- else if (key == "^W-KEY_LEFT" || key == "^W-H")
- return changeWindow(-1, false);
- return inputResult::nextInput;
- }
- bool CurseOutput::redraw(const std::string &errorMsg)
- {
- bool result = redraw();
- writeBottomLine(errorMsg, OutputFlag::SPECIAL_ERROR);
- return result;
- }
- unsigned int CurseOutput::write(const int &x, const int &y, JSonElement *item, unsigned int maxWidth, OutputFlag flags)
- {
- return write(x, y, item->stringify(), item->lazystrlen(), maxWidth, flags);
- }
- unsigned int CurseOutput::getNbLines(const size_t nbChar, unsigned int maxWidth)
- {
- double nLine = (double) nbChar / maxWidth;
- if (nLine == (unsigned int) nLine)
- return nLine;
- return nLine +1;
- }
- bool CurseOutput::hasReachedBottom(unsigned int pos, unsigned int scrollTop, unsigned int height) const
- {
- return (pos >= scrollTop && (pos -scrollTop) > height -1);
- }
- const t_Cursor CurseOutput::getScreenSizeUnsafe() const
- {
- t_Cursor bs;
- t_Cursor sc;
- getmaxyx(stdscr, sc.second, sc.first);
- getbegyx(stdscr, bs.second, bs.first);
- sc.first -= bs.first;
- sc.second -= bs.second;
- return sc;
- }
- void CurseOutput::unfold(const JSonElement *item)
- {
- while (item->getParent())
- {
- collapsed.erase((const JSonContainer*)item->getParent());
- item = item->getParent();
- }
- }
- const SearchPattern *CurseOutput::inputSearch()
- {
- std::wstring buffer;
- bool abort = false;
- curs_set(true);
- wtimeout(stdscr, -1);
- while (!abort)
- {
- int c;
- writeBottomLine(L'/' +buffer, OutputFlag::SPECIAL_SEARCH);
- refresh();
- c = getwchar();
- if (c == L'\r')
- break;
- else if (c == L'\b' || c == 127)
- {
- if (!buffer.empty())
- buffer.pop_back();
- }
- else if (c == 27)
- abort = true;
- else
- buffer += c;
- }
- wtimeout(stdscr, 150);
- curs_set(false);
- {
- const size_t size = buffer.size();
- char bytesString[size * sizeof(wchar_t)];
- wcstombs(&bytesString[0], buffer.c_str(), sizeof(bytesString));
- std::string str;
- if (params.isIgnoringUnicode())
- str = bytesString;
- else
- str = StreamConsumer::extractUnicode(bytesString);
- return abort ? nullptr : new SearchPattern(str);
- }
- }
- void CurseOutput::writeTopLine(const std::string &buffer, short color) const
- {
- const std::string str = buffer.substr(0, screenSize.first);
- const size_t bufsize = str.size();
- if (params.colorEnabled())
- attron(COLOR_PAIR(color));
- mvprintw(0, 0, "%s%*c", str.c_str(), screenSize.first - bufsize, ' ');
- if (params.colorEnabled())
- attroff(COLOR_PAIR(color));
- }
- void CurseOutput::writeBottomLine(const std::string &buffer, short color) const
- {
- const t_Cursor screenSize = getScreenSizeUnsafe();
- const size_t bufsize = buffer.size();
- if (params.colorEnabled())
- attron(COLOR_PAIR(color));
- mvprintw(screenSize.second -1, 0, "%s%*c", buffer.c_str(), screenSize.first - bufsize, ' ');
- move(screenSize.second -1, bufsize);
- if (params.colorEnabled())
- attroff(COLOR_PAIR(color));
- }
- void CurseOutput::writeBottomLine(const std::wstring &buffer, short color) const
- {
- const t_Cursor screenSize = getScreenSizeUnsafe();
- const size_t bufsize = buffer.size();
- if (params.colorEnabled())
- attron(COLOR_PAIR(color));
- mvprintw(screenSize.second -1, 0, "%S%*c", buffer.c_str(), screenSize.first - bufsize, ' ');
- move(screenSize.second -1, bufsize);
- if (params.colorEnabled())
- attroff(COLOR_PAIR(color));
- }
- void CurseOutput::init()
- {
- if (!isatty(fileno(stdin)) || !isatty(fileno(stdout)))
- {
- screen_fd = fopen("/dev/tty", "r+");
- setbuf(screen_fd, nullptr);
- screen = newterm(nullptr, screen_fd, screen_fd);
- }
- else
- {
- screen = newterm(nullptr, stdout, stdin);
- screen_fd = nullptr;
- }
- wtimeout(stdscr, 150);
- cbreak();
- clear();
- noecho();
- curs_set(false);
- keypad(stdscr, true);
- screenSize = getScreenSize();
- if (params.colorEnabled())
- {
- start_color();
- init_pair(OutputFlag::TYPE_NUMBER, COLOR_GREEN, COLOR_BLACK);
- init_pair(OutputFlag::TYPE_BOOL, COLOR_RED, COLOR_BLACK);
- init_pair(OutputFlag::TYPE_NULL, COLOR_RED, COLOR_BLACK);
- init_pair(OutputFlag::TYPE_STRING, COLOR_CYAN, COLOR_BLACK);
- init_pair(OutputFlag::TYPE_OBJKEY, COLOR_CYAN, COLOR_BLACK);
- init_pair(OutputFlag::SPECIAL_SEARCH, COLOR_WHITE, COLOR_BLUE);
- init_pair(OutputFlag::SPECIAL_ERROR, COLOR_WHITE, COLOR_RED);
- init_pair(OutputFlag::SPECIAL_ACTIVEINPUTNAME, COLOR_BLACK, COLOR_GREEN);
- init_pair(OutputFlag::SPECIAL_INPUTNAME, COLOR_BLACK, COLOR_WHITE);
- init_pair(OutputFlag::DIFF_ADD, COLOR_GREEN, COLOR_BLACK);
- init_pair(OutputFlag::DIFF_MOD, COLOR_CYAN, COLOR_BLACK);
- init_pair(OutputFlag::DIFF_REM, COLOR_MAGENTA, COLOR_BLACK);
- colors.insert(OutputFlag::TYPE_NUMBER);
- colors.insert(OutputFlag::TYPE_BOOL);
- colors.insert(OutputFlag::TYPE_STRING);
- colors.insert(OutputFlag::TYPE_OBJKEY);
- colors.insert(OutputFlag::TYPE_NULL);
- }
- signal(SIGWINCH, _resizeFnc);
- signal(SIGINT, _resizeFnc);
- signal(SIGTERM, _resizeFnc);
- signal(SIGKILL, _resizeFnc);
- signal(SIGCONT, _resizeFnc);
- }
|