forked from lix-project/lix
util.{hh,cc}: Split out terminal.{hh,cc}
Change-Id: I9de2296b4012d50f540124001d54d6ca3be4c6da
This commit is contained in:
parent
6fd6795bc4
commit
81bdf8d2d6
|
@ -1,6 +1,7 @@
|
||||||
#include "markdown.hh"
|
#include "markdown.hh"
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "finally.hh"
|
#include "finally.hh"
|
||||||
|
#include "terminal.hh"
|
||||||
|
|
||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
#include <lowdown.h>
|
#include <lowdown.h>
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "fetchers.hh"
|
#include "fetchers.hh"
|
||||||
#include "finally.hh"
|
#include "finally.hh"
|
||||||
#include "fetch-settings.hh"
|
#include "fetch-settings.hh"
|
||||||
|
#include "terminal.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "english.hh"
|
#include "english.hh"
|
||||||
#include "signals.hh"
|
#include "signals.hh"
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
|
#include "terminal.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "sync.hh"
|
#include "sync.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
#include "names.hh"
|
#include "names.hh"
|
||||||
|
#include "terminal.hh"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "environment-variables.hh"
|
#include "environment-variables.hh"
|
||||||
#include "error.hh"
|
#include "error.hh"
|
||||||
#include "position.hh"
|
#include "position.hh"
|
||||||
|
#include "terminal.hh"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "config.hh"
|
#include "config.hh"
|
||||||
#include "source-path.hh"
|
#include "source-path.hh"
|
||||||
#include "position.hh"
|
#include "position.hh"
|
||||||
|
#include "terminal.hh"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
|
@ -30,6 +30,7 @@ libutil_sources = files(
|
||||||
'source-path.cc',
|
'source-path.cc',
|
||||||
'suggestions.cc',
|
'suggestions.cc',
|
||||||
'tarfile.cc',
|
'tarfile.cc',
|
||||||
|
'terminal.cc',
|
||||||
'thread-pool.cc',
|
'thread-pool.cc',
|
||||||
'url.cc',
|
'url.cc',
|
||||||
'url-name.cc',
|
'url-name.cc',
|
||||||
|
@ -90,6 +91,7 @@ libutil_headers = files(
|
||||||
'suggestions.hh',
|
'suggestions.hh',
|
||||||
'sync.hh',
|
'sync.hh',
|
||||||
'tarfile.hh',
|
'tarfile.hh',
|
||||||
|
'terminal.hh',
|
||||||
'thread-pool.hh',
|
'thread-pool.hh',
|
||||||
'topo-sort.hh',
|
'topo-sort.hh',
|
||||||
'types.hh',
|
'types.hh',
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "error.hh"
|
#include "error.hh"
|
||||||
#include "sync.hh"
|
#include "sync.hh"
|
||||||
|
#include "terminal.hh"
|
||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#include "suggestions.hh"
|
#include "suggestions.hh"
|
||||||
#include "ansicolor.hh"
|
#include "ansicolor.hh"
|
||||||
#include "util.hh"
|
#include "terminal.hh"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
104
src/libutil/terminal.cc
Normal file
104
src/libutil/terminal.cc
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
#include "terminal.hh"
|
||||||
|
#include "environment-variables.hh"
|
||||||
|
#include "sync.hh"
|
||||||
|
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
bool shouldANSI()
|
||||||
|
{
|
||||||
|
return isatty(STDERR_FILENO)
|
||||||
|
&& getEnv("TERM").value_or("dumb") != "dumb"
|
||||||
|
&& !(getEnv("NO_COLOR").has_value() || getEnv("NOCOLOR").has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string filterANSIEscapes(std::string_view s, bool filterAll, unsigned int width)
|
||||||
|
{
|
||||||
|
std::string t, e;
|
||||||
|
size_t w = 0;
|
||||||
|
auto i = s.begin();
|
||||||
|
|
||||||
|
while (w < (size_t) width && i != s.end()) {
|
||||||
|
|
||||||
|
if (*i == '\e') {
|
||||||
|
std::string e;
|
||||||
|
e += *i++;
|
||||||
|
char last = 0;
|
||||||
|
|
||||||
|
if (i != s.end() && *i == '[') {
|
||||||
|
e += *i++;
|
||||||
|
// eat parameter bytes
|
||||||
|
while (i != s.end() && *i >= 0x30 && *i <= 0x3f) e += *i++;
|
||||||
|
// eat intermediate bytes
|
||||||
|
while (i != s.end() && *i >= 0x20 && *i <= 0x2f) e += *i++;
|
||||||
|
// eat final byte
|
||||||
|
if (i != s.end() && *i >= 0x40 && *i <= 0x7e) e += last = *i++;
|
||||||
|
} else {
|
||||||
|
if (i != s.end() && *i >= 0x40 && *i <= 0x5f) e += *i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filterAll && last == 'm')
|
||||||
|
t += e;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (*i == '\t') {
|
||||||
|
i++; t += ' '; w++;
|
||||||
|
while (w < (size_t) width && w % 8) {
|
||||||
|
t += ' '; w++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (*i == '\r' || *i == '\a')
|
||||||
|
// do nothing for now
|
||||||
|
i++;
|
||||||
|
|
||||||
|
else {
|
||||||
|
w++;
|
||||||
|
// Copy one UTF-8 character.
|
||||||
|
if ((*i & 0xe0) == 0xc0) {
|
||||||
|
t += *i++;
|
||||||
|
if (i != s.end() && ((*i & 0xc0) == 0x80)) t += *i++;
|
||||||
|
} else if ((*i & 0xf0) == 0xe0) {
|
||||||
|
t += *i++;
|
||||||
|
if (i != s.end() && ((*i & 0xc0) == 0x80)) {
|
||||||
|
t += *i++;
|
||||||
|
if (i != s.end() && ((*i & 0xc0) == 0x80)) t += *i++;
|
||||||
|
}
|
||||||
|
} else if ((*i & 0xf8) == 0xf0) {
|
||||||
|
t += *i++;
|
||||||
|
if (i != s.end() && ((*i & 0xc0) == 0x80)) {
|
||||||
|
t += *i++;
|
||||||
|
if (i != s.end() && ((*i & 0xc0) == 0x80)) {
|
||||||
|
t += *i++;
|
||||||
|
if (i != s.end() && ((*i & 0xc0) == 0x80)) t += *i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
t += *i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Sync<std::pair<unsigned short, unsigned short>> windowSize{{0, 0}};
|
||||||
|
|
||||||
|
void updateWindowSize()
|
||||||
|
{
|
||||||
|
struct winsize ws;
|
||||||
|
if (ioctl(2, TIOCGWINSZ, &ws) == 0) {
|
||||||
|
auto windowSize_(windowSize.lock());
|
||||||
|
windowSize_->first = ws.ws_row;
|
||||||
|
windowSize_->second = ws.ws_col;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::pair<unsigned short, unsigned short> getWindowSize()
|
||||||
|
{
|
||||||
|
return *windowSize.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
40
src/libutil/terminal.hh
Normal file
40
src/libutil/terminal.hh
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#pragma once
|
||||||
|
///@file
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether ANSI escape sequences are appropriate for the
|
||||||
|
* present output.
|
||||||
|
*/
|
||||||
|
bool shouldANSI();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Truncate a string to 'width' printable characters. If 'filterAll'
|
||||||
|
* is true, all ANSI escape sequences are filtered out. Otherwise,
|
||||||
|
* some escape sequences (such as colour setting) are copied but not
|
||||||
|
* included in the character count. Also, tabs are expanded to
|
||||||
|
* spaces.
|
||||||
|
*/
|
||||||
|
std::string filterANSIEscapes(std::string_view s,
|
||||||
|
bool filterAll = false,
|
||||||
|
unsigned int width = std::numeric_limits<unsigned int>::max());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recalculate the window size, updating a global variable. Used in the
|
||||||
|
* `SIGWINCH` signal handler.
|
||||||
|
*/
|
||||||
|
void updateWindowSize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the number of rows and columns of the terminal.
|
||||||
|
*
|
||||||
|
* The value is cached so this is quick. The cached result is computed
|
||||||
|
* by `updateWindowSize()`.
|
||||||
|
*/
|
||||||
|
std::pair<unsigned short, unsigned short> getWindowSize();
|
||||||
|
|
||||||
|
}
|
|
@ -1436,83 +1436,6 @@ void ignoreException(Verbosity lvl)
|
||||||
} catch (...) { }
|
} catch (...) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
bool shouldANSI()
|
|
||||||
{
|
|
||||||
return isatty(STDERR_FILENO)
|
|
||||||
&& getEnv("TERM").value_or("dumb") != "dumb"
|
|
||||||
&& !(getEnv("NO_COLOR").has_value() || getEnv("NOCOLOR").has_value());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string filterANSIEscapes(std::string_view s, bool filterAll, unsigned int width)
|
|
||||||
{
|
|
||||||
std::string t, e;
|
|
||||||
size_t w = 0;
|
|
||||||
auto i = s.begin();
|
|
||||||
|
|
||||||
while (w < (size_t) width && i != s.end()) {
|
|
||||||
|
|
||||||
if (*i == '\e') {
|
|
||||||
std::string e;
|
|
||||||
e += *i++;
|
|
||||||
char last = 0;
|
|
||||||
|
|
||||||
if (i != s.end() && *i == '[') {
|
|
||||||
e += *i++;
|
|
||||||
// eat parameter bytes
|
|
||||||
while (i != s.end() && *i >= 0x30 && *i <= 0x3f) e += *i++;
|
|
||||||
// eat intermediate bytes
|
|
||||||
while (i != s.end() && *i >= 0x20 && *i <= 0x2f) e += *i++;
|
|
||||||
// eat final byte
|
|
||||||
if (i != s.end() && *i >= 0x40 && *i <= 0x7e) e += last = *i++;
|
|
||||||
} else {
|
|
||||||
if (i != s.end() && *i >= 0x40 && *i <= 0x5f) e += *i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!filterAll && last == 'm')
|
|
||||||
t += e;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (*i == '\t') {
|
|
||||||
i++; t += ' '; w++;
|
|
||||||
while (w < (size_t) width && w % 8) {
|
|
||||||
t += ' '; w++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (*i == '\r' || *i == '\a')
|
|
||||||
// do nothing for now
|
|
||||||
i++;
|
|
||||||
|
|
||||||
else {
|
|
||||||
w++;
|
|
||||||
// Copy one UTF-8 character.
|
|
||||||
if ((*i & 0xe0) == 0xc0) {
|
|
||||||
t += *i++;
|
|
||||||
if (i != s.end() && ((*i & 0xc0) == 0x80)) t += *i++;
|
|
||||||
} else if ((*i & 0xf0) == 0xe0) {
|
|
||||||
t += *i++;
|
|
||||||
if (i != s.end() && ((*i & 0xc0) == 0x80)) {
|
|
||||||
t += *i++;
|
|
||||||
if (i != s.end() && ((*i & 0xc0) == 0x80)) t += *i++;
|
|
||||||
}
|
|
||||||
} else if ((*i & 0xf8) == 0xf0) {
|
|
||||||
t += *i++;
|
|
||||||
if (i != s.end() && ((*i & 0xc0) == 0x80)) {
|
|
||||||
t += *i++;
|
|
||||||
if (i != s.end() && ((*i & 0xc0) == 0x80)) {
|
|
||||||
t += *i++;
|
|
||||||
if (i != s.end() && ((*i & 0xc0) == 0x80)) t += *i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
t += *i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
constexpr char base64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
constexpr char base64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
|
||||||
std::string base64Encode(std::string_view s)
|
std::string base64Encode(std::string_view s)
|
||||||
|
@ -1630,25 +1553,6 @@ std::pair<std::string_view, std::string_view> getLine(std::string_view s)
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static Sync<std::pair<unsigned short, unsigned short>> windowSize{{0, 0}};
|
|
||||||
|
|
||||||
|
|
||||||
void updateWindowSize()
|
|
||||||
{
|
|
||||||
struct winsize ws;
|
|
||||||
if (ioctl(2, TIOCGWINSZ, &ws) == 0) {
|
|
||||||
auto windowSize_(windowSize.lock());
|
|
||||||
windowSize_->first = ws.ws_row;
|
|
||||||
windowSize_->second = ws.ws_col;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::pair<unsigned short, unsigned short> getWindowSize()
|
|
||||||
{
|
|
||||||
return *windowSize.lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
rlim_t savedStackSize = 0;
|
rlim_t savedStackSize = 0;
|
||||||
|
|
||||||
|
|
|
@ -726,23 +726,6 @@ constexpr char treeLast[] = "└───";
|
||||||
constexpr char treeLine[] = "│ ";
|
constexpr char treeLine[] = "│ ";
|
||||||
constexpr char treeNull[] = " ";
|
constexpr char treeNull[] = " ";
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether ANSI escape sequences are appropriate for the
|
|
||||||
* present output.
|
|
||||||
*/
|
|
||||||
bool shouldANSI();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Truncate a string to 'width' printable characters. If 'filterAll'
|
|
||||||
* is true, all ANSI escape sequences are filtered out. Otherwise,
|
|
||||||
* some escape sequences (such as colour setting) are copied but not
|
|
||||||
* included in the character count. Also, tabs are expanded to
|
|
||||||
* spaces.
|
|
||||||
*/
|
|
||||||
std::string filterANSIEscapes(std::string_view s,
|
|
||||||
bool filterAll = false,
|
|
||||||
unsigned int width = std::numeric_limits<unsigned int>::max());
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base64 encoding/decoding.
|
* Base64 encoding/decoding.
|
||||||
|
@ -840,14 +823,6 @@ struct MaintainCount
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the number of rows and columns of the terminal.
|
|
||||||
*/
|
|
||||||
std::pair<unsigned short, unsigned short> getWindowSize();
|
|
||||||
|
|
||||||
void updateWindowSize();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used in various places.
|
* Used in various places.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "types.hh"
|
#include "types.hh"
|
||||||
|
#include "terminal.hh"
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
Loading…
Reference in a new issue