339 lines · 8.8 KB · C++
RawDownload
/* This file is part of Zutty. * Copyright (C) 2020 Tom Szilagyi * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * See the file LICENSE for the full license. */ #include "frame.h"#include "log.h" namespace zutty{   Frame::Frame () {}    Frame::Frame (uint16_t winPx_, uint16_t winPy_,                 uint16_t nCols_, uint16_t nRows_,                 uint16_t& marginTop_, uint16_t& marginBottom_,                 uint16_t saveLines_)      : winPx (winPx_)      , winPy (winPy_)      , nCols (nCols_)      , nRows (nRows_)      , saveLines (saveLines_)      , scrollHead (0)      , marginTop (0)      , marginBottom (nRows + saveLines)      , historyRows (0)      , viewOffset (0)      , margins (false)      , cells (CharVdev::make_cells (nCols, nRows + saveLines))   {      marginTop_ = marginTop;      marginBottom_ = nRows;      damage.totalCells = nCols * (nRows + saveLines);      highMemUsageReport ();   }    void   Frame::dropScrollbackHistory ()   {      viewOffset = 0;      historyRows = 0;      expose ();   }    void   Frame::setMargins (uint16_t marginTop_, uint16_t marginBottom_)   {      unwrapCellStorage ();      scrollHead = marginTop = marginTop_;      marginBottom = marginBottom_;      margins = true;      expose ();   }    void   Frame::resetMargins (uint16_t& marginTop_, uint16_t& marginBottom_)   {      unwrapCellStorage ();      scrollHead = marginTop = marginTop_ = 0;      marginBottom = nRows + saveLines;      marginBottom_ = nRows;      margins = false;      expose ();   }    void   Frame::resize (uint16_t winPx_, uint16_t winPy_,                  uint16_t nCols_, uint16_t nRows_,                  uint16_t& marginTop_, uint16_t& marginBottom_)   {      if (winPx == winPx_ && winPy == winPy_)         return;       winPx = winPx_;      winPy = winPy_;       if (nCols == nCols_ && nRows == nRows_)         return;       auto newCells = CharVdev::make_cells (nCols_, nRows_ + saveLines);      CharVdev::Cell* dst = newCells.get ();       const int rowLen = std::min (nCols, nCols_);      const int nCopyRows = std::min (nRows, nRows_);      CharVdev::Cell* p = dst;      for (int pY = 0; pY < nCopyRows; ++pY)      {         memcpy (p, getPhysRowPtr (pY), rowLen * cellSize);         p += nCols_;      }      p = dst + (nRows_ + saveLines - historyRows) * nCols_;      for (int pY = -historyRows; pY < 0; ++pY)      {         memcpy (p, getPhysRowPtr (pY), rowLen * cellSize);         p += nCols_;      }       cells = std::move (newCells);      nCols = nCols_;      nRows = nRows_;      scrollHead = 0;      marginTop = marginTop_ = 0;      marginBottom_ = nRows;      marginBottom = nRows + saveLines;      margins = false;      viewOffset = 0;      damage.totalCells = nCols * (nRows + saveLines);      highMemUsageReport ();   }    void   Frame::fullCopyCells (CharVdev::Cell * const dst)   {      CharVdev::Cell* p = dst;      for (int pY = 0; pY < nRows; ++pY)      {         memcpy (p, getViewRowPtr (pY), nCols * cellSize);         p += nCols;      }   }    void   Frame::deltaCopyCells (CharVdev::Cell * const dst)   {      CharVdev::Cell* p = dst;      for (int pY = -viewOffset; pY < nRows - viewOffset; ++pY)      {         damageDeltaCopy (p, nCols * getPhysicalRow (pY), nCols);         p += nCols;      }   }    Rect   Frame::getSnappedSelection () const   {      Rect ret = selection;       if (ret.null ())         return ret;       if (selection.rectangular)         return ret;       switch (snapTo)      {      case SelectSnapTo::Char:         break;      case SelectSnapTo::Word:      {         const auto* cp = getViewRowPtr (ret.tl.y);         while (ret.tl.x < nCols && cp [ret.tl.x].uc_pt == ' ')            ++ret.tl.x;         while (ret.tl.x > 0 && cp [ret.tl.x - 1].uc_pt != ' ')            --ret.tl.x;          cp = getViewRowPtr (ret.br.y);         while (ret.br.x > 0 && cp [ret.br.x].uc_pt == ' ')            --ret.br.x;         while (ret.br.x < nCols && cp [ret.br.x].uc_pt != ' ')            ++ret.br.x;      }         break;      case SelectSnapTo::Line:         ret.tl.x = 0;         ret.br.x = nCols;         break;      default: break;      }       return ret;   }    bool   Frame::getSelectedUtf8 (std::string& utf8_selection) const   {      const Rect sel = getSnappedSelection ();       if (sel.empty ())         return false;       using utf16str = std::vector <uint16_t>;      std::vector <utf16str> lines;      bool wrap = false;       // save lines from the selected range of the frame cell buffer      auto addLine =         [&] (int y, uint16_t x1, uint16_t x2)         {            utf16str line;            bool wrapBack = wrap;            wrap = false;            const auto* cp = getViewRowPtr (y);            for (uint16_t x = x1; x < x2; ++x)            {               const auto& cell = cp [x];               if (!cell.dwidth_cont)                  line.push_back (cell.uc_pt);               if (cell.wrap)               {                  wrap = true;                  break;               }            }             while (!wrap && line.size () && line.back () == ' ')               line.pop_back (); // discard trailing whitespace             if (wrapBack && lines.size ())               lines.back ().insert (lines.back ().end (),                                     line.begin (), line.end ());            else               lines.push_back (line);         };       if (sel.tl.y == sel.br.y)      {         addLine (sel.tl.y, sel.tl.x, sel.br.x);      }      else if (sel.rectangular)      {         for (int y = sel.tl.y; y <= sel.br.y; ++y)            addLine (y, sel.tl.x, sel.br.x);      }      else      {         addLine (sel.tl.y, sel.tl.x, nCols);         for (int y = sel.tl.y + 1; y < sel.br.y; ++y)            addLine (y, 0, nCols);         addLine (sel.br.y, 0, sel.br.x);      }       // convert to UTF-8      std::vector <char> utf8_out;      auto sinkFn = [&] (char ch) { utf8_out.push_back (ch); };      for (const auto& u16s: lines)      {         for (uint16_t cp: u16s)            Utf8Encoder::pushUnicode (cp, sinkFn);         utf8_out.push_back ('\n');      }      while (utf8_out.size () && utf8_out.back () == '\n')         utf8_out.pop_back (); // discard trailing empty lines       utf8_selection = std::string (utf8_out.data (), utf8_out.size ());    #if DEBUG      if (utf8_selection.size () <= 80)         logT << "Selected " << utf8_selection.size () << " bytes:\n'"              << utf8_selection << "'" << std::endl;      else         logT << "Selected " << utf8_selection.size () << " bytes:\n'"              << utf8_selection.substr (0, 40) << "' ...\n'"              << utf8_selection.substr (utf8_selection.size () - 40) << "'"              << std::endl;   #endif // DEBUG      return true;   }    // private functions    inline void   Frame::damageDeltaCopy (CharVdev::Cell* dst, uint32_t start, uint32_t count)   {      uint32_t end = start + count;       if (damage.end <= start || end <= damage.start)         return; // no intersection       if (start < damage.start)      {         dst += (damage.start - start);         start = damage.start;      }       if (damage.end < end)      {         end = damage.end;      }       CharVdev::Cell* const src = cells.get ();       for (size_t i = 0, j = start; j < end; ++i, ++j)      {         if (dst [i] != src [j])         {            dst [i] = src [j];            dst [i].dirty = 1;         }      }   }    void   Frame::copyAllCells (CharVdev::Cell * const dst)   {      CharVdev::Cell* p = dst;      for (int pY = 0; pY < nRows; ++pY)      {         memcpy (p, getPhysRowPtr (pY), nCols * cellSize);         p += nCols;      }      p = dst + (nRows + saveLines - historyRows) * nCols;      for (int pY = -historyRows; pY < 0; ++pY)      {         memcpy (p, getPhysRowPtr (pY), nCols * cellSize);         p += nCols;      }   }    void   Frame::unwrapCellStorage ()   {      if (scrollHead == marginTop)         return;       auto newCells = CharVdev::make_cells (nCols, nRows + saveLines);      copyAllCells (newCells.get ());      cells = std::move (newCells);      scrollHead = marginTop;   }    void   Frame::highMemUsageReport ()   {      auto allocKB = damage.totalCells * cellSize / 1024;      if (allocKB > 8192)      {         logI << "Allocated " << allocKB << " KiB for cell storage; consider "              << "decreasing saveLines (current value: " << saveLines              << ") to reduce memory usage!"              << std::endl;      }   } } // namespace zutty

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t