From 341301e9ab41537730462238ff8c5ae85509e668 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Mon, 21 Mar 2016 14:20:39 +1100 Subject: [PATCH] term: add trivial ANSI colour escapes --- Makefile.am | 2 + term.cpp | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++ term.hpp | 68 ++++++++++++++++++++++++++ 3 files changed, 206 insertions(+) create mode 100644 term.cpp create mode 100644 term.hpp diff --git a/Makefile.am b/Makefile.am index c1838d3a..24163764 100644 --- a/Makefile.am +++ b/Makefile.am @@ -247,6 +247,8 @@ UTIL_FILES = \ tap.cpp \ tap.hpp \ tap.ipp \ + term.cpp \ + term.hpp \ time.cpp \ time.hpp \ tuple.cpp \ diff --git a/term.cpp b/term.cpp new file mode 100644 index 00000000..a6b923b2 --- /dev/null +++ b/term.cpp @@ -0,0 +1,136 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2016 Danny Robson + */ + +#include "./term.hpp" + +#include "./string.hpp" + +#include +#include +#include + +using util::term::csi::graphics; + + +static const boost::filesystem::path DEFAULT_SEARCH_DIR = "/usr/share/terminfo"; + +constexpr char util::term::csi::code::CSI; + +const graphics graphics::RESET (0); + + +/////////////////////////////////////////////////////////////////////////////// +// find the terminfo path within a directory, for a key +// +// throws an exception if not found +static +boost::filesystem::path +find_terminfo_path (const boost::filesystem::path &dir, + const std::string &key) +{ + const char letter[2] = { key[0], '\0' }; + auto candidate = dir / letter / key; + + if (!boost::filesystem::is_directory (candidate)) + throw std::runtime_error ("path not found"); + + return candidate; +} + + +//----------------------------------------------------------------------------- +// find the terminfo path for a given key. +// +// throws an exception if not found +static +boost::filesystem::path +find_terminfo_path (const std::string &key) +{ + // check if the path is explicitly listed. must not fall through. + if (const char *dir = getenv ("TERMINFO")) { + return find_terminfo_path (dir, key); + } + + // check if we have a path at $HOME. falls through. + if (const char *home = getenv ("HOME")) { + boost::filesystem::path HOME (home); + try { + return find_terminfo_path (HOME / ".terminfo", key); + } catch (...) { } + } + + // check colon seperated list in TERMINFO_DIRS + if (const char *dirs = getenv ("TERMINFO_DIRS")) { + auto tok = util::make_tokeniser (dirs, ':'); + + for (auto i: tok) { + try { + return find_terminfo_path ( + i.empty () ? + DEFAULT_SEARCH_DIR : + boost::filesystem::path (i.cbegin (), i.cend ()), key + ); + } catch (...) { } + } + } + + return find_terminfo_path ("/usr/share/terminfo", key); +} + + +/////////////////////////////////////////////////////////////////////////////// +bool +util::term::has_csi_support (void) +{ + // HACK: this will do until we get a terminfo/termcap reader + return getenv ("TERM") == std::string ("XTERM"); +} + + +/////////////////////////////////////////////////////////////////////////////// +graphics::graphics (layer _layer, hue _hue): + m_value (_layer + _hue) +{ ; } + + +//----------------------------------------------------------------------------- +graphics::graphics (char _value): + m_value (_value) +{ ; } + + +/////////////////////////////////////////////////////////////////////////////// +char +graphics::value (void) const +{ + return m_value; +} + + +//----------------------------------------------------------------------------- +char +graphics::value (char _value) +{ + return m_value = _value; +} + + +/////////////////////////////////////////////////////////////////////////////// +std::ostream& +util::term::csi::operator<< (std::ostream &os, graphics g) +{ + return os << code::CSI << '[' << +g.value () << decltype(g)::terminator; +} diff --git a/term.hpp b/term.hpp new file mode 100644 index 00000000..70132c70 --- /dev/null +++ b/term.hpp @@ -0,0 +1,68 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2016 Danny Robson + */ + +#ifndef __UTIL_TERM_HPP +#define __UTIL_TERM_HPP + +#include + +namespace util { namespace term { + bool has_csi_support (void); + + namespace csi { + struct code { + static constexpr char CSI = '\x1B'; + }; + + + struct graphics : public code { + static constexpr char terminator = 'm'; + + enum layer { + FOREGROUND = 30, + BACKGROUND = 40 + }; + + enum hue { + BLACK = 0, + RED = 1, + GREEN = 2, + YELLOW = 3, + BLUE = 4, + MAGENTA = 5, + CYAN = 6, + WHITE = 7, + }; + + graphics (layer, hue); + explicit graphics (char value); + + char value (void) const; + char value (char); + + static const graphics RESET; + + private: + char m_value; + }; + + + std::ostream& operator<< (std::ostream&, code); + std::ostream& operator<< (std::ostream&, graphics); + } +} } + +#endif