summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxime Coste <mawww@kakoune.org>2019-11-13 23:31:24 +1100
committerMaxime Coste <mawww@kakoune.org>2021-07-12 10:25:58 +1000
commitc12699d2e9c2806d6ed184032078d0b84a3370bb (patch)
tree1ad90cb6a81dc9f5d195864ac040bad7dbd83c4a /src
parent911edf6ea30a78d63a8aa80bb6261c42e46a2c34 (diff)
Replace ncurses with a naive custom terminal backend
Diffstat (limited to 'src')
-rw-r--r--src/main.cc2
-rw-r--r--src/ncurses_ui.cc419
-rw-r--r--src/ncurses_ui.hh46
3 files changed, 141 insertions, 326 deletions
diff --git a/src/main.cc b/src/main.cc
index 28de0063..ad4088d6 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -1000,7 +1000,7 @@ int run_pipe(StringView session)
void signal_handler(int signal)
{
- NCursesUI::abort();
+ NCursesUI::restore_terminal();
const char* text = nullptr;
switch (signal)
{
diff --git a/src/ncurses_ui.cc b/src/ncurses_ui.cc
index 0f865970..8fc6d614 100644
--- a/src/ncurses_ui.cc
+++ b/src/ncurses_ui.cc
@@ -10,11 +10,6 @@
#include <algorithm>
-#define NCURSES_OPAQUE 0
-#define NCURSES_INTERNALS
-
-#include <ncurses.h>
-
#include <fcntl.h>
#include <csignal>
#include <sys/ioctl.h>
@@ -29,94 +24,110 @@ namespace Kakoune
using std::min;
using std::max;
-struct NCursesWin : WINDOW {};
+static void set_cursor_pos(DisplayCoord coord)
+{
+ printf("\033[%d;%dH", (int)coord.line + 1, (int)coord.column + 1);
+}
void NCursesUI::Window::create(const DisplayCoord& p, const DisplayCoord& s)
{
pos = p;
size = s;
- win = (NCursesWin*)newpad((int)size.line, (int)size.column);
+ lines.resize((int)size.line);
}
void NCursesUI::Window::destroy()
{
- delwin(win);
- win = nullptr;
pos = DisplayCoord{};
size = DisplayCoord{};
+ lines.clear();
}
void NCursesUI::Window::refresh(bool force)
{
- if (not win)
+ if (lines.empty())
return;
- if (force)
- redrawwin(win);
+ static constexpr int fg_table[]{ 39, 30, 31, 32, 33, 34, 35, 36, 37, 90, 91, 92, 93, 94, 95, 96, 97 };
+ static constexpr int bg_table[]{ 49, 40, 41, 42, 43, 44, 45, 46, 47, 100, 101, 102, 103, 104, 105, 106, 107 };
+ static constexpr int attr_table[]{ 0, 4, 7, 5, 1, 2, 3 };
+ auto set_color = [](bool fg, const Color& color) {
+ if (color.isRGB())
+ printf(";%d;2;%d;%d;%d", fg ? 38 : 48, color.r, color.g, color.b);
+ else
+ printf(";%d", (fg ? fg_table : bg_table)[(int)(char)color.color]);
+ };
- DisplayCoord max_pos = pos + size - DisplayCoord{1,1};
- pnoutrefresh(win, 0, 0, (int)pos.line, (int)pos.column,
- (int)max_pos.line, (int)max_pos.column);
+ auto set_attributes = [](const Attribute& attributes) {
+ for (int i = 0; i < sizeof(attr_table) / sizeof(int); ++i)
+ {
+ if (attributes & (Attribute)(1 << i))
+ printf(";%d", attr_table[i]);
+ }
+ };
+
+ DisplayCoord cursor_pos = pos;
+ for (auto& line : lines)
+ {
+ set_cursor_pos(cursor_pos);
+ for (auto& atom : line)
+ {
+ printf("\033[");
+ set_attributes(atom.face.attributes);
+ set_color(true, atom.face.fg);
+ set_color(false, atom.face.bg);
+ printf("m");
+ fputs(atom.text.c_str(), stdout);
+ }
+ ++cursor_pos.line;
+ }
}
void NCursesUI::Window::move_cursor(DisplayCoord coord)
{
- wmove(win, (int)coord.line, (int)coord.column);
+ cursor = coord;
}
-void NCursesUI::Window::draw(Palette& palette, ConstArrayView<DisplayAtom> atoms,
- const Face& default_face)
+void NCursesUI::Window::clear_line()
{
- auto add_str = [&](StringView str) { waddnstr(win, str.begin(), (int)str.length()); };
-
- auto set_face = [&](Face face) {
- if (m_active_pair != -1)
- wattroff(win, COLOR_PAIR(m_active_pair));
-
- face = merge_faces(default_face, face);
-
- if (face.fg != Color::Default or face.bg != Color::Default)
- {
- m_active_pair = palette.get_color_pair(face);
- wattron(win, COLOR_PAIR(m_active_pair));
- }
-
- auto set_attribute = [&](Attribute attr, int nc_attr) {
- (face.attributes & attr) ? wattron(win, nc_attr) : wattroff(win, nc_attr);
- };
-
- set_attribute(Attribute::Underline, A_UNDERLINE);
- set_attribute(Attribute::Reverse, A_REVERSE);
- set_attribute(Attribute::Blink, A_BLINK);
- set_attribute(Attribute::Bold, A_BOLD);
- set_attribute(Attribute::Dim, A_DIM);
- #if defined(A_ITALIC)
- set_attribute(Attribute::Italic, A_ITALIC);
- #endif
- };
-
- wbkgdset(win, COLOR_PAIR(palette.get_color_pair(default_face)));
+ auto& line = lines[(int)cursor.line];
+ auto it = line.begin();
+ ColumnCount column = 0;
+ for (; it != line.end() and column < cursor.column; ++it)
+ column += it->text.column_length();
+
+ line.erase(it, line.end());
+ if (column > cursor.column)
+ {
+ auto& text = line.back().text;
+ auto new_length = text.column_length() - (column - cursor.column);
+ text.resize(text.byte_count_to(new_length), 0);
+ }
+}
- ColumnCount column = getcurx(win);
+void NCursesUI::Window::draw(ConstArrayView<DisplayAtom> atoms,
+ const Face& default_face)
+{
+ clear_line();
for (const DisplayAtom& atom : atoms)
{
StringView content = atom.content();
if (content.empty())
continue;
- set_face(atom.face);
+ auto face = merge_faces(default_face, atom.face);
if (content.back() == '\n')
{
- add_str(content.substr(0, content.length()-1));
- waddch(win, ' ');
+ lines[(int)cursor.line].push_back({content.substr(0, content.length()-1).str(), face});
+ lines[(int)cursor.line].push_back({" ", face});
}
else
- add_str(content);
- column += content.column_length();
+ lines[(int)cursor.line].push_back({content.str(), face});
+ cursor.column += content.column_length();
}
- if (column < size.column)
- wclrtoeol(win);
+ if (cursor.column < size.column)
+ lines[(int)cursor.line].push_back({String(' ', size.column - cursor.column), default_face});
}
constexpr int NCursesUI::default_shift_function_key;
@@ -158,163 +169,6 @@ static constexpr StringView assistant_dilbert[] =
template<typename T> T sq(T x) { return x * x; }
-constexpr struct { unsigned char r, g, b; } builtin_colors[] = {
- {0x00,0x00,0x00}, {0x80,0x00,0x00}, {0x00,0x80,0x00}, {0x80,0x80,0x00},
- {0x00,0x00,0x80}, {0x80,0x00,0x80}, {0x00,0x80,0x80}, {0xc0,0xc0,0xc0},
- {0x80,0x80,0x80}, {0xff,0x00,0x00}, {0x00,0xff,0x00}, {0xff,0xff,0x00},
- {0x00,0x00,0xff}, {0xff,0x00,0xff}, {0x00,0xff,0xff}, {0xff,0xff,0xff},
- {0x00,0x00,0x00}, {0x00,0x00,0x5f}, {0x00,0x00,0x87}, {0x00,0x00,0xaf},
- {0x00,0x00,0xd7}, {0x00,0x00,0xff}, {0x00,0x5f,0x00}, {0x00,0x5f,0x5f},
- {0x00,0x5f,0x87}, {0x00,0x5f,0xaf}, {0x00,0x5f,0xd7}, {0x00,0x5f,0xff},
- {0x00,0x87,0x00}, {0x00,0x87,0x5f}, {0x00,0x87,0x87}, {0x00,0x87,0xaf},
- {0x00,0x87,0xd7}, {0x00,0x87,0xff}, {0x00,0xaf,0x00}, {0x00,0xaf,0x5f},
- {0x00,0xaf,0x87}, {0x00,0xaf,0xaf}, {0x00,0xaf,0xd7}, {0x00,0xaf,0xff},
- {0x00,0xd7,0x00}, {0x00,0xd7,0x5f}, {0x00,0xd7,0x87}, {0x00,0xd7,0xaf},
- {0x00,0xd7,0xd7}, {0x00,0xd7,0xff}, {0x00,0xff,0x00}, {0x00,0xff,0x5f},
- {0x00,0xff,0x87}, {0x00,0xff,0xaf}, {0x00,0xff,0xd7}, {0x00,0xff,0xff},
- {0x5f,0x00,0x00}, {0x5f,0x00,0x5f}, {0x5f,0x00,0x87}, {0x5f,0x00,0xaf},
- {0x5f,0x00,0xd7}, {0x5f,0x00,0xff}, {0x5f,0x5f,0x00}, {0x5f,0x5f,0x5f},
- {0x5f,0x5f,0x87}, {0x5f,0x5f,0xaf}, {0x5f,0x5f,0xd7}, {0x5f,0x5f,0xff},
- {0x5f,0x87,0x00}, {0x5f,0x87,0x5f}, {0x5f,0x87,0x87}, {0x5f,0x87,0xaf},
- {0x5f,0x87,0xd7}, {0x5f,0x87,0xff}, {0x5f,0xaf,0x00}, {0x5f,0xaf,0x5f},
- {0x5f,0xaf,0x87}, {0x5f,0xaf,0xaf}, {0x5f,0xaf,0xd7}, {0x5f,0xaf,0xff},
- {0x5f,0xd7,0x00}, {0x5f,0xd7,0x5f}, {0x5f,0xd7,0x87}, {0x5f,0xd7,0xaf},
- {0x5f,0xd7,0xd7}, {0x5f,0xd7,0xff}, {0x5f,0xff,0x00}, {0x5f,0xff,0x5f},
- {0x5f,0xff,0x87}, {0x5f,0xff,0xaf}, {0x5f,0xff,0xd7}, {0x5f,0xff,0xff},
- {0x87,0x00,0x00}, {0x87,0x00,0x5f}, {0x87,0x00,0x87}, {0x87,0x00,0xaf},
- {0x87,0x00,0xd7}, {0x87,0x00,0xff}, {0x87,0x5f,0x00}, {0x87,0x5f,0x5f},
- {0x87,0x5f,0x87}, {0x87,0x5f,0xaf}, {0x87,0x5f,0xd7}, {0x87,0x5f,0xff},
- {0x87,0x87,0x00}, {0x87,0x87,0x5f}, {0x87,0x87,0x87}, {0x87,0x87,0xaf},
- {0x87,0x87,0xd7}, {0x87,0x87,0xff}, {0x87,0xaf,0x00}, {0x87,0xaf,0x5f},
- {0x87,0xaf,0x87}, {0x87,0xaf,0xaf}, {0x87,0xaf,0xd7}, {0x87,0xaf,0xff},
- {0x87,0xd7,0x00}, {0x87,0xd7,0x5f}, {0x87,0xd7,0x87}, {0x87,0xd7,0xaf},
- {0x87,0xd7,0xd7}, {0x87,0xd7,0xff}, {0x87,0xff,0x00}, {0x87,0xff,0x5f},
- {0x87,0xff,0x87}, {0x87,0xff,0xaf}, {0x87,0xff,0xd7}, {0x87,0xff,0xff},
- {0xaf,0x00,0x00}, {0xaf,0x00,0x5f}, {0xaf,0x00,0x87}, {0xaf,0x00,0xaf},
- {0xaf,0x00,0xd7}, {0xaf,0x00,0xff}, {0xaf,0x5f,0x00}, {0xaf,0x5f,0x5f},
- {0xaf,0x5f,0x87}, {0xaf,0x5f,0xaf}, {0xaf,0x5f,0xd7}, {0xaf,0x5f,0xff},
- {0xaf,0x87,0x00}, {0xaf,0x87,0x5f}, {0xaf,0x87,0x87}, {0xaf,0x87,0xaf},
- {0xaf,0x87,0xd7}, {0xaf,0x87,0xff}, {0xaf,0xaf,0x00}, {0xaf,0xaf,0x5f},
- {0xaf,0xaf,0x87}, {0xaf,0xaf,0xaf}, {0xaf,0xaf,0xd7}, {0xaf,0xaf,0xff},
- {0xaf,0xd7,0x00}, {0xaf,0xd7,0x5f}, {0xaf,0xd7,0x87}, {0xaf,0xd7,0xaf},
- {0xaf,0xd7,0xd7}, {0xaf,0xd7,0xff}, {0xaf,0xff,0x00}, {0xaf,0xff,0x5f},
- {0xaf,0xff,0x87}, {0xaf,0xff,0xaf}, {0xaf,0xff,0xd7}, {0xaf,0xff,0xff},
- {0xd7,0x00,0x00}, {0xd7,0x00,0x5f}, {0xd7,0x00,0x87}, {0xd7,0x00,0xaf},
- {0xd7,0x00,0xd7}, {0xd7,0x00,0xff}, {0xd7,0x5f,0x00}, {0xd7,0x5f,0x5f},
- {0xd7,0x5f,0x87}, {0xd7,0x5f,0xaf}, {0xd7,0x5f,0xd7}, {0xd7,0x5f,0xff},
- {0xd7,0x87,0x00}, {0xd7,0x87,0x5f}, {0xd7,0x87,0x87}, {0xd7,0x87,0xaf},
- {0xd7,0x87,0xd7}, {0xd7,0x87,0xff}, {0xd7,0xaf,0x00}, {0xd7,0xaf,0x5f},
- {0xd7,0xaf,0x87}, {0xd7,0xaf,0xaf}, {0xd7,0xaf,0xd7}, {0xd7,0xaf,0xff},
- {0xd7,0xd7,0x00}, {0xd7,0xd7,0x5f}, {0xd7,0xd7,0x87}, {0xd7,0xd7,0xaf},
- {0xd7,0xd7,0xd7}, {0xd7,0xd7,0xff}, {0xd7,0xff,0x00}, {0xd7,0xff,0x5f},
- {0xd7,0xff,0x87}, {0xd7,0xff,0xaf}, {0xd7,0xff,0xd7}, {0xd7,0xff,0xff},
- {0xff,0x00,0x00}, {0xff,0x00,0x5f}, {0xff,0x00,0x87}, {0xff,0x00,0xaf},
- {0xff,0x00,0xd7}, {0xff,0x00,0xff}, {0xff,0x5f,0x00}, {0xff,0x5f,0x5f},
- {0xff,0x5f,0x87}, {0xff,0x5f,0xaf}, {0xff,0x5f,0xd7}, {0xff,0x5f,0xff},
- {0xff,0x87,0x00}, {0xff,0x87,0x5f}, {0xff,0x87,0x87}, {0xff,0x87,0xaf},
- {0xff,0x87,0xd7}, {0xff,0x87,0xff}, {0xff,0xaf,0x00}, {0xff,0xaf,0x5f},
- {0xff,0xaf,0x87}, {0xff,0xaf,0xaf}, {0xff,0xaf,0xd7}, {0xff,0xaf,0xff},
- {0xff,0xd7,0x00}, {0xff,0xd7,0x5f}, {0xff,0xd7,0x87}, {0xff,0xd7,0xaf},
- {0xff,0xd7,0xd7}, {0xff,0xd7,0xff}, {0xff,0xff,0x00}, {0xff,0xff,0x5f},
- {0xff,0xff,0x87}, {0xff,0xff,0xaf}, {0xff,0xff,0xd7}, {0xff,0xff,0xff},
- {0x08,0x08,0x08}, {0x12,0x12,0x12}, {0x1c,0x1c,0x1c}, {0x26,0x26,0x26},
- {0x30,0x30,0x30}, {0x3a,0x3a,0x3a}, {0x44,0x44,0x44}, {0x4e,0x4e,0x4e},
- {0x58,0x58,0x58}, {0x60,0x60,0x60}, {0x66,0x66,0x66}, {0x76,0x76,0x76},
- {0x80,0x80,0x80}, {0x8a,0x8a,0x8a}, {0x94,0x94,0x94}, {0x9e,0x9e,0x9e},
- {0xa8,0xa8,0xa8}, {0xb2,0xb2,0xb2}, {0xbc,0xbc,0xbc}, {0xc6,0xc6,0xc6},
- {0xd0,0xd0,0xd0}, {0xda,0xda,0xda}, {0xe4,0xe4,0xe4}, {0xee,0xee,0xee},
-};
-
-const std::initializer_list<HashMap<Kakoune::Color, int>::Item>
-NCursesUI::Palette::default_colors = {
- { Color::Default, -1 },
- { Color::Black, 0 },
- { Color::Red, 1 },
- { Color::Green, 2 },
- { Color::Yellow, 3 },
- { Color::Blue, 4 },
- { Color::Magenta, 5 },
- { Color::Cyan, 6 },
- { Color::White, 7 },
- { Color::BrightBlack, 8 },
- { Color::BrightRed, 9 },
- { Color::BrightGreen, 10 },
- { Color::BrightYellow, 11 },
- { Color::BrightBlue, 12 },
- { Color::BrightMagenta, 13 },
- { Color::BrightCyan, 14 },
- { Color::BrightWhite, 15 },
-};
-
-int NCursesUI::Palette::get_color(Color color)
-{
- auto it = m_colors.find(color);
- if (it != m_colors.end())
- return it->value;
- else if (m_change_colors and can_change_color() and COLORS > 16)
- {
- kak_assert(color.isRGB());
- if (m_next_color > COLORS)
- m_next_color = 16;
- init_color(m_next_color,
- color.r * 1000 / 255,
- color.g * 1000 / 255,
- color.b * 1000 / 255);
- m_colors[color] = m_next_color;
- return m_next_color++;
- }
- else
- {
- kak_assert(color.isRGB());
- int lowestDist = INT_MAX;
- int closestCol = -1;
- for (int i = 0; i < std::min(256, COLORS); ++i)
- {
- auto& col = builtin_colors[i];
- int dist = sq(color.r - col.r)
- + sq(color.g - col.g)
- + sq(color.b - col.b);
- if (dist < lowestDist)
- {
- lowestDist = dist;
- closestCol = i;
- }
- }
- return closestCol;
- }
-}
-
-int NCursesUI::Palette::get_color_pair(const Face& face)
-{
- ColorPair colors{face.fg, face.bg};
- auto it = m_colorpairs.find(colors);
- if (it != m_colorpairs.end())
- return it->value;
- else
- {
- init_pair(m_next_pair, get_color(face.fg), get_color(face.bg));
- m_colorpairs[colors] = m_next_pair;
- return m_next_pair++;
- }
-}
-
-bool NCursesUI::Palette::set_change_colors(bool change_colors)
-{
- bool reset = false;
- if (can_change_color() and m_change_colors != change_colors)
- {
- fputs("\033]104\007", stdout); // try to reset palette
- fflush(stdout);
- m_colorpairs.clear();
- m_colors = default_colors;
- m_next_color = 16;
- m_next_pair = 1;
- reset = true;
- }
- m_change_colors = change_colors;
- return reset;
-}
-
static sig_atomic_t resize_pending = 0;
static sig_atomic_t stdin_closed = 0;
@@ -347,12 +201,8 @@ NCursesUI::NCursesUI()
tcgetattr(STDIN_FILENO, &m_original_termios);
- initscr();
- curs_set(0);
- start_color();
- use_default_colors();
-
- set_terminal_mode();
+ setup_terminal();
+ set_raw_mode();
enable_mouse(true);
set_signal_handler(SIGWINCH, &signal_handler<&resize_pending>);
@@ -366,9 +216,8 @@ NCursesUI::NCursesUI()
NCursesUI::~NCursesUI()
{
enable_mouse(false);
- m_palette.set_change_colors(false);
- restore_terminal_mode();
- endwin();
+ restore_terminal();
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &m_original_termios);
set_signal_handler(SIGWINCH, SIG_DFL);
set_signal_handler(SIGHUP, SIG_DFL);
set_signal_handler(SIGTSTP, SIG_DFL);
@@ -378,16 +227,13 @@ void NCursesUI::suspend()
{
bool mouse_enabled = m_mouse_enabled;
enable_mouse(false);
- bool change_color_enabled = m_palette.get_change_colors();
- m_palette.set_change_colors(false);
+ restore_terminal();
auto current = set_signal_handler(SIGTSTP, SIG_DFL);
sigset_t unblock_sigtstp, old_mask;
sigemptyset(&unblock_sigtstp);
sigaddset(&unblock_sigtstp, SIGTSTP);
sigprocmask(SIG_UNBLOCK, &unblock_sigtstp, &old_mask);
- restore_terminal_mode();
- endwin();
raise(SIGTSTP); // suspend here
@@ -395,14 +241,15 @@ void NCursesUI::suspend()
set_signal_handler(SIGTSTP, current);
sigprocmask(SIG_SETMASK, &old_mask, nullptr);
- doupdate();
+ setup_terminal();
check_resize(true);
- set_terminal_mode();
- m_palette.set_change_colors(change_color_enabled);
+ set_raw_mode();
enable_mouse(mouse_enabled);
+
+ refresh(true);
}
-void NCursesUI::set_terminal_mode() const
+void NCursesUI::set_raw_mode() const
{
termios attr = m_original_termios;
attr.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
@@ -414,24 +261,6 @@ void NCursesUI::set_terminal_mode() const
attr.c_cc[VMIN] = attr.c_cc[VTIME] = 0;
tcsetattr(STDIN_FILENO, TCSANOW, &attr);
- fputs("\033=", stdout);
- // force enable report focus events
- fputs("\033[?1004h", stdout);
- // request CSI u style key reporting
- fputs("\033[>4;1m", stdout);
- // save the current window title
- fputs("\033[22t", stdout);
- fflush(stdout);
-}
-
-void NCursesUI::restore_terminal_mode() const
-{
- tcsetattr(STDIN_FILENO, TCSAFLUSH, &m_original_termios);
- fputs("\033>", stdout);
- fputs("\033[?1004l", stdout);
- fputs("\033[>4;0m", stdout);
- fputs("\033[23t", stdout);
- fflush(stdout);
}
void NCursesUI::redraw(bool force)
@@ -443,13 +272,12 @@ void NCursesUI::redraw(bool force)
m_info.refresh(false);
- Window screen{{}, static_cast<NCursesWin*>(newscr)};
if (m_cursor.mode == CursorMode::Prompt)
- screen.move_cursor({m_status_on_top ? 0 : m_dimensions.line, m_cursor.coord.column});
+ set_cursor_pos({m_status_on_top ? 0 : m_dimensions.line, m_cursor.coord.column});
else
- screen.move_cursor(m_cursor.coord + content_line_offset());
+ set_cursor_pos(m_cursor.coord + content_line_offset());
- doupdate();
+ fflush(stdout);
}
void NCursesUI::set_cursor(CursorMode mode, DisplayCoord coord)
@@ -478,24 +306,17 @@ void NCursesUI::draw(const DisplayBuffer& display_buffer,
for (const DisplayLine& line : display_buffer.lines())
{
m_window.move_cursor(line_index++);
- m_window.draw(m_palette, line.atoms(), default_face);
+ m_window.draw(line.atoms(), default_face);
}
auto face = merge_faces(default_face, padding_face);
while (line_index < dim.line + line_offset)
{
m_window.move_cursor(line_index++);
- if (m_padding_fill)
- {
- ColumnCount column_index = 0;
- while (column_index < dim.column)
- {
- m_window.draw(m_palette, m_padding_char, face);
- column_index += m_padding_char.length();
- }
- }
- else
- m_window.draw(m_palette, m_padding_char, face);
+ m_window.draw(m_padding_char, face);
+ const auto padding_len = m_padding_char.length();
+ for (auto col = padding_len; m_padding_fill and col < dim.column; col += padding_len)
+ m_window.draw(m_padding_char, face);
}
m_dirty = true;
@@ -508,7 +329,7 @@ void NCursesUI::draw_status(const DisplayLine& status_line,
const LineCount status_line_pos = m_status_on_top ? 0 : m_dimensions.line;
m_window.move_cursor(status_line_pos);
- m_window.draw(m_palette, status_line.atoms(), default_face);
+ m_window.draw(status_line.atoms(), default_face);
const auto mode_len = mode_line.length();
m_status_len = status_line.length();
@@ -517,7 +338,7 @@ void NCursesUI::draw_status(const DisplayLine& status_line,
{
ColumnCount col = m_dimensions.column - mode_len;
m_window.move_cursor({status_line_pos, col});
- m_window.draw(m_palette, mode_line.atoms(), default_face);
+ m_window.draw(mode_line.atoms(), default_face);
}
else if (remaining > 2)
{
@@ -528,7 +349,7 @@ void NCursesUI::draw_status(const DisplayLine& status_line,
ColumnCount col = m_dimensions.column - remaining + 1;
m_window.move_cursor({status_line_pos, col});
- m_window.draw(m_palette, trimmed_mode_line.atoms(), default_face);
+ m_window.draw(trimmed_mode_line.atoms(), default_face);
}
if (m_set_title)
@@ -576,15 +397,13 @@ void NCursesUI::check_resize(bool force)
if (info) m_info.destroy();
if (menu) m_menu.destroy();
- resize_term(ws.ws_row, ws.ws_col);
-
m_window.create({0, 0}, {ws.ws_row, ws.ws_col});
kak_assert(m_window);
m_dimensions = DisplayCoord{ws.ws_row-1, ws.ws_col};
- if (char* csr = tigetstr((char*)"csr"))
- putp(tparm(csr, 0, ws.ws_row));
+ // if (char* csr = tigetstr((char*)"csr"))
+ // putp(tparm(csr, 0, ws.ws_row));
if (menu)
menu_show(Vector<DisplayLine>(std::move(m_menu.items)),
@@ -593,7 +412,6 @@ void NCursesUI::check_resize(bool force)
info_show(m_info.title, m_info.content, m_info.anchor, m_info.face, m_info.style);
set_resize_pending();
- wclear(curscr);
}
Optional<Key> NCursesUI::get_next_key()
@@ -897,7 +715,7 @@ void NCursesUI::draw_menu()
ColumnCount pos = 0;
m_menu.move_cursor({0, 0});
- m_menu.draw(m_palette, DisplayAtom(m_menu.first_item > 0 ? "< " : " "), m_menu.bg);
+ m_menu.draw(DisplayAtom(m_menu.first_item > 0 ? "< " : " "), m_menu.bg);
int i = m_menu.first_item;
for (; i < item_count and pos < win_width; ++i)
@@ -905,19 +723,19 @@ void NCursesUI::draw_menu()
const DisplayLine& item = m_menu.items[i];
const ColumnCount item_width = item.length();
auto& face = i == m_menu.selected_item ? m_menu.fg : m_menu.bg;
- m_menu.draw(m_palette, item.atoms(), face);
+ m_menu.draw(item.atoms(), face);
if (pos + item_width < win_width)
- m_menu.draw(m_palette, DisplayAtom(" "), m_menu.bg);
+ m_menu.draw(DisplayAtom(" "), m_menu.bg);
else
{
m_menu.move_cursor({0, win_width+2});
- m_menu.draw(m_palette, DisplayAtom("…"), m_menu.bg);
+ m_menu.draw(DisplayAtom("…"), m_menu.bg);
}
pos += item_width + 1;
}
m_menu.move_cursor({0, win_width+3});
- m_menu.draw(m_palette, DisplayAtom(i == item_count ? " " : ">"), m_menu.bg);
+ m_menu.draw(DisplayAtom(i == item_count ? " " : ">"), m_menu.bg);
m_dirty = true;
return;
@@ -945,11 +763,11 @@ void NCursesUI::draw_menu()
int item_idx = (first_col + col) * (int)m_menu.size.line + (int)line;
auto& face = item_idx < item_count and item_idx == m_menu.selected_item ? m_menu.fg : m_menu.bg;
auto atoms = item_idx < item_count ? m_menu.items[item_idx].atoms() : ConstArrayView<DisplayAtom>{};
- m_menu.draw(m_palette, atoms, face);
+ m_menu.draw(atoms, face);
}
const bool is_mark = line >= mark_line and line < mark_line + mark_height;
m_menu.move_cursor({line, m_menu.size.column - 1});
- m_menu.draw(m_palette, DisplayAtom(is_mark ? "█" : "░"), m_menu.bg);
+ m_menu.draw(DisplayAtom(is_mark ? "█" : "░"), m_menu.bg);
}
m_dirty = true;
}
@@ -1245,8 +1063,8 @@ void NCursesUI::info_show(const DisplayLine& title, const DisplayLineList& conte
m_info.create(anchor, size);
auto draw_atoms = [&](auto&&... args) {
auto draw = overload(
- [&](String str) { m_info.draw(m_palette, DisplayAtom{std::move(str)}, face); },
- [&](const DisplayLine& atoms) { m_info.draw(m_palette, atoms.atoms(), face); });
+ [&](String str) { m_info.draw(DisplayAtom{std::move(str)}, face); },
+ [&](const DisplayLine& atoms) { m_info.draw(atoms.atoms(), face); });
(draw(args), ...);
};
@@ -1324,9 +1142,35 @@ void NCursesUI::set_resize_pending()
EventManager::instance().force_signal(0);
}
-void NCursesUI::abort()
+void NCursesUI::setup_terminal()
{
- endwin();
+ // enable alternative screen buffer
+ fputs("\033[?1049h", stdout);
+ // enable focus notify
+ fputs("\033[?1004h", stdout);
+ // request CSI u style key reporting
+ fputs("\033[>4;1m", stdout);
+ // save the current window title
+ fputs("\033[22t", stdout);
+ // hide cursor
+ fputs("\033[?25l", stdout);
+ // set application keypad mode, so the keypad keys send unique codes
+ fputs("\033=", stdout);
+ fflush(stdout);
+}
+
+void NCursesUI::restore_terminal()
+{
+ fputs("\033>", stdout);
+ fputs("\033[?25h", stdout);
+ fputs("\033[23t", stdout);
+ fputs("\033[>4;0m", stdout);
+ fputs("\033[?1004l", stdout);
+ fputs("\033[?1049l", stdout);
+
+ // set the terminal output back to default colours and style
+ fputs("\033[m", stdout);
+ fflush(stdout);
}
void NCursesUI::enable_mouse(bool enabled)
@@ -1387,17 +1231,6 @@ void NCursesUI::set_ui_options(const Options& options)
}
{
- auto it = options.find("ncurses_change_colors"_sv);
- if (m_palette.set_change_colors(it == options.end() or
- (it->value == "yes" or it->value == "true")))
- {
- m_window.m_active_pair = -1;
- m_menu.m_active_pair = -1;
- m_info.m_active_pair = -1;
- }
- }
-
- {
auto enable_mouse_it = options.find("ncurses_enable_mouse"_sv);
enable_mouse(enable_mouse_it == options.end() or
enable_mouse_it->value == "yes" or
diff --git a/src/ncurses_ui.hh b/src/ncurses_ui.hh
index 4cc354cd..0a7cef7c 100644
--- a/src/ncurses_ui.hh
+++ b/src/ncurses_ui.hh
@@ -18,8 +18,6 @@ namespace Kakoune
struct DisplayAtom;
-struct NCursesWin;
-
class NCursesUI : public UserInterface, public Singleton<NCursesUI>
{
public:
@@ -58,7 +56,8 @@ public:
void set_on_key(OnKeyCallback callback) override;
void set_ui_options(const Options& options) override;
- static void abort();
+ static void setup_terminal();
+ static void restore_terminal();
void suspend();
@@ -74,41 +73,25 @@ private:
Optional<Key> get_next_key();
- struct Palette
- {
- private:
- static const std::initializer_list<HashMap<Kakoune::Color, int>::Item> default_colors;
-
- using ColorPair = std::pair<Color, Color>;
- HashMap<Color, int, MemoryDomain::Faces> m_colors = default_colors;
- HashMap<ColorPair, int, MemoryDomain::Faces> m_colorpairs;
- int m_next_color = 16;
- int m_next_pair = 1;
- bool m_change_colors = true;
-
- int get_color(Color color);
-
- public:
- int get_color_pair(const Face& face);
- bool get_change_colors() const { return m_change_colors; }
- bool set_change_colors(bool change_colors);
- };
-
- Palette m_palette;
-
struct Window : Rect
{
void create(const DisplayCoord& pos, const DisplayCoord& size);
void destroy();
void refresh(bool force);
void move_cursor(DisplayCoord coord);
- void draw(Palette& palette, ConstArrayView<DisplayAtom> atoms,
- const Face& default_face);
+ void draw(ConstArrayView<DisplayAtom> atoms, const Face& default_face);
+
+ explicit operator bool() const { return not lines.empty(); }
- explicit operator bool() const { return win; }
+ struct Atom
+ {
+ String text;
+ Face face;
+ };
+ Vector<Vector<Atom>> lines;
+ DisplayCoord cursor;
- NCursesWin* win = nullptr;
- int m_active_pair = -1;
+ void clear_line();
};
Window m_window;
@@ -116,8 +99,7 @@ private:
DisplayCoord m_dimensions;
termios m_original_termios{};
- void set_terminal_mode() const;
- void restore_terminal_mode() const;
+ void set_raw_mode() const;
struct Menu : Window
{