Skip to content

Commit

Permalink
Basic implementation of a buffer list
Browse files Browse the repository at this point in the history
This commit adds a second bar under/above the status bar (according to the
`ncurses_status_on_top` UI option) which lists all the buffers opened. The
bar is rendered using the -now default- `BufList` face, and the display name
of the currently open buffer will be rendered using the -now default as well-
`BufListCurrent` face.

Menus take precedence over this buffer list, which means the bar will not be
displayed when an interactive selection is necessary (e.g. when completing
a command name and candidates show up), but other information boxes such
as the `autoinfo` will be rendered under the buffer bar.

This feature is disabled by default and has to be activated using the
`ncurses_buflist_show` UI option.
  • Loading branch information
lenormf committed Dec 23, 2016
1 parent d17bed9 commit 3986d18
Show file tree
Hide file tree
Showing 12 changed files with 194 additions and 7 deletions.
2 changes: 2 additions & 0 deletions colors/default.kak
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ face StatusLineMode yellow,default
face StatusLineInfo blue,default
face StatusLineValue green,default
face StatusCursor black,cyan
face BufList StatusLine
face BufListCurrent cyan,default+r
face Prompt yellow,default
face MatchingChar default,default+b
face BufferPadding blue,default
33 changes: 32 additions & 1 deletion src/client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ void Client::print_status(DisplayLine status_line, bool immediate)
}
}


DisplayCoord Client::dimensions() const
{
return m_ui->dimensions();
Expand Down Expand Up @@ -145,6 +144,26 @@ DisplayLine Client::generate_mode_line() const
return modeline;
}

DisplayLine Client::generate_buflist() const
{
DisplayLine buflist;
Face buflist_face = get_face("BufList");
Face buflist_current_face = get_face("BufListCurrent");

auto* current_buffer = &m_window->buffer();
const String current_buffer_name = current_buffer->name();
for (auto it = BufferManager::instance().begin(); it != BufferManager::instance().end(); it++)
{
const bool is_current_buffer = current_buffer_name == (*it)->name();
const DisplayAtom atom_buffer = DisplayAtom((*it)->display_name(),
is_current_buffer ? buflist_current_face : buflist_face);

buflist.push_back(atom_buffer);
}

return buflist;
}

void Client::change_buffer(Buffer& buffer)
{
if (m_buffer_reload_dialog_opened)
Expand Down Expand Up @@ -193,6 +212,15 @@ void Client::redraw_ifn()
m_mode_line = std::move(mode_line);
}

// FIXME: when the separator is changed in the UI options, the buflist needs to be redrawn;
// falling through when the set_ui_options has set the Draw flag might not be the best thing to do
DisplayLine buflist = generate_buflist();
if (buflist.atoms() != m_buflist.atoms() || (m_ui_pending & Draw))
{
m_ui_pending |= BufList;
m_buflist = std::move(buflist);
}

if (m_ui_pending == 0)
return;

Expand Down Expand Up @@ -235,6 +263,9 @@ void Client::redraw_ifn()
if (m_ui_pending & StatusLine)
m_ui->draw_status(m_status_line, m_mode_line, get_face("StatusLine"));

if (m_ui_pending & BufList)
m_ui->draw_buflist(m_buflist, get_face("BufList"));

m_ui->refresh(m_ui_pending | Refresh);
m_ui_pending = 0;
}
Expand Down
7 changes: 5 additions & 2 deletions src/client.hh
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ private:
Optional<Key> get_next_key(EventMode mode);

DisplayLine generate_mode_line() const;
DisplayLine generate_buflist() const;

std::unique_ptr<UserInterface> m_ui;
std::unique_ptr<Window> m_window;
Expand All @@ -85,6 +86,7 @@ private:

DisplayLine m_status_line;
DisplayLine m_mode_line;
DisplayLine m_buflist;

enum PendingUI : int
{
Expand All @@ -94,8 +96,9 @@ private:
InfoShow = 1 << 3,
InfoHide = 1 << 4,
StatusLine = 1 << 5,
Draw = 1 << 6,
Refresh = 1 << 7,
BufList = 1 << 6,
Draw = 1 << 7,
Refresh = 1 << 8,
};
int m_ui_pending = 0;

Expand Down
8 changes: 8 additions & 0 deletions src/display_buffer.hh
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ class DisplayLine : public UseMemoryDomain<MemoryDomain::Display>
public:
using iterator = AtomList::iterator;
using const_iterator = AtomList::const_iterator;
using reverse_iterator = AtomList::reverse_iterator;
using const_reverse_iterator = AtomList::const_reverse_iterator;
using value_type = AtomList::value_type;

DisplayLine() = default;
Expand All @@ -115,6 +117,12 @@ public:
const_iterator begin() const { return m_atoms.begin(); }
const_iterator end() const { return m_atoms.end(); }

reverse_iterator rbegin() { return m_atoms.rbegin(); }
reverse_iterator rend() { return m_atoms.rend(); }

const_reverse_iterator rbegin() const { return m_atoms.rbegin(); }
const_reverse_iterator rend() const { return m_atoms.rend(); }

const AtomList& atoms() const { return m_atoms; }

ColumnCount length() const;
Expand Down
2 changes: 2 additions & 0 deletions src/face_registry.cc
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ FaceRegistry::FaceRegistry()
{ "StatusLineInfo", Face{ Color::Blue, Color::Default } },
{ "StatusLineValue", Face{ Color::Green, Color::Default } },
{ "StatusCursor", Face{ Color::Black, Color::Cyan } },
{ "BufList", Face{ Color::Cyan, Color::Default } },
{ "BufListCurrent", Face{ Color::Cyan, Color::Default, Attribute::Reverse } },
{ "Prompt", Face{ Color::Yellow, Color::Default } },
{ "MatchingChar", Face{ Color::Default, Color::Default, Attribute::Bold } },
{ "BufferPadding", Face{ Color::Blue, Color::Default } },
Expand Down
6 changes: 6 additions & 0 deletions src/json_ui.cc
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,12 @@ void JsonUI::draw_status(const DisplayLine& status_line,
rpc_call("draw_status", status_line, mode_line, default_face);
}

void JsonUI::draw_buflist(const DisplayLine& buflist,
const Face& default_face)
{
rpc_call("draw_buflist", buflist, default_face);
}


void JsonUI::menu_show(ConstArrayView<DisplayLine> items,
DisplayCoord anchor, Face fg, Face bg,
Expand Down
3 changes: 3 additions & 0 deletions src/json_ui.hh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ public:
const DisplayLine& mode_line,
const Face& default_face) override;

void draw_buflist(const DisplayLine& buflist,
const Face& default_face) override;

void menu_show(ConstArrayView<DisplayLine> items,
DisplayCoord anchor, Face fg, Face bg,
MenuStyle style) override;
Expand Down
1 change: 1 addition & 0 deletions src/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ std::unique_ptr<UserInterface> make_ui(UIType ui_type)

void draw(const DisplayBuffer&, const Face&, const Face&) override {}
void draw_status(const DisplayLine&, const DisplayLine&, const Face&) override {}
void draw_buflist(const DisplayLine&, const Face&) override {}
DisplayCoord dimensions() override { return {24,80}; }
void refresh(bool) override {}
void set_on_key(OnKeyCallback callback) override {}
Expand Down
110 changes: 106 additions & 4 deletions src/ncurses_ui.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
#include <termios.h>
#include <unistd.h>

// FIXME: remove
#include "buffer_utils.hh"

constexpr char control(char c) { return c & 037; }

namespace Kakoune
Expand Down Expand Up @@ -359,7 +362,7 @@ void NCursesUI::draw(const DisplayBuffer& display_buffer,

check_resize();

LineCount line_index = m_status_on_top ? 1 : 0;
LineCount line_index = m_status_on_top ? (m_buflist_show ? 2 : 1) : 0;
for (const DisplayLine& line : display_buffer.lines())
{
wmove(m_window, (int)line_index, 0);
Expand All @@ -381,11 +384,97 @@ void NCursesUI::draw(const DisplayBuffer& display_buffer,
m_dirty = true;
}

static DisplayLine::const_reverse_iterator find_current_buffer_r(const DisplayLine& buflist,
const Face& default_face)
{
for (auto it = buflist.rbegin(); it != buflist.rend(); it++)
if (it->face != default_face)
return it;

return buflist.rend();
}

static DisplayLine::const_iterator find_current_buffer(const DisplayLine& buflist,
const Face& default_face)
{
for (auto it = buflist.begin(); it != buflist.end(); it++)
if (it->face != default_face)
return it;

return buflist.end();
}

void NCursesUI::draw_buflist(const DisplayLine& buflist_particles,
const Face& default_face)
{
const int buflist_pos = m_status_on_top ? 1 : (int)m_dimensions.line;
const DisplayAtom atom_separator = DisplayAtom(m_buflist_separator, default_face);
DisplayLine buflist;

if (!m_buflist_show)
return;

{
DisplayLine::const_reverse_iterator it_current_buffer_r;
it_current_buffer_r = find_current_buffer_r(buflist_particles, default_face);
kak_assert(it_current_buffer_r != buflist_particles.rend());

const int head_point = (int)m_dimensions.column - (int)it_current_buffer_r->length();

buflist.push_back(*it_current_buffer_r);
for (auto it = it_current_buffer_r + 1; it != buflist_particles.rend(); it++)
{
const ColumnCount length_buflist_proj = buflist.length() + it->length()
+ m_buflist_separator.column_count_to(m_buflist_separator.length());

if (length_buflist_proj > head_point)
{
if (length_buflist_proj - head_point >= 1)
buflist.insert(buflist.begin(), DisplayAtom("", default_face));
break;
}
buflist.insert(buflist.begin(), atom_separator);
buflist.insert(buflist.begin(), *it);
}
}

{
DisplayLine::const_iterator it_current_buffer;
it_current_buffer = find_current_buffer(buflist_particles, default_face);
kak_assert(it_current_buffer != buflist_particles.end());

for (auto it = it_current_buffer + 1; it != buflist_particles.end(); it++)
{
const ColumnCount length_buflist_proj = buflist.length() + it->length()
+ m_buflist_separator.column_count_to(m_buflist_separator.length());

if (length_buflist_proj > m_dimensions.column)
{
if (length_buflist_proj - m_dimensions.column >= 1)
buflist.push_back(DisplayAtom("", default_face));
break;
}
buflist.push_back(atom_separator);
buflist.push_back(*it);
}
}

wmove(m_window, buflist_pos, 0);
wbkgdset(m_window, COLOR_PAIR(get_color_pair(default_face)));
wclrtoeol(m_window);

wmove(m_window, buflist_pos, 0);

draw_line(m_window, buflist, 0, m_dimensions.column, default_face);

m_dirty = true;
}

void NCursesUI::draw_status(const DisplayLine& status_line,
const DisplayLine& mode_line,
const Face& default_face)
{
const int status_line_pos = m_status_on_top ? 0 : (int)m_dimensions.line;
const int status_line_pos = m_status_on_top ? 0 : (int)m_dimensions.line + 1;
wmove(m_window, status_line_pos, 0);

wbkgdset(m_window, COLOR_PAIR(get_color_pair(default_face)));
Expand Down Expand Up @@ -460,7 +549,7 @@ void NCursesUI::check_resize(bool force)
intrflush(m_window, false);
keypad(m_window, true);

m_dimensions = DisplayCoord{ws.ws_row-1, ws.ws_col};
m_dimensions = DisplayCoord{ws.ws_row-2, ws.ws_col};

if (char* csr = tigetstr((char*)"csr"))
putp(tparm(csr, 0, ws.ws_row));
Expand Down Expand Up @@ -528,7 +617,9 @@ Optional<Key> NCursesUI::get_next_key()
};

return Key{ get_modifiers(ev.bstate),
encode_coord({ ev.y - (m_status_on_top ? 1 : 0), ev.x }) };
encode_coord({ ev.y - (m_status_on_top ? (m_buflist_show ? 2 : 1)
: (m_buflist_show ? 1 : 0)),
ev.x }) };
}
}

Expand Down Expand Up @@ -1009,6 +1100,17 @@ void NCursesUI::set_ui_options(const Options& options)
(it->value == "yes" or it->value == "true");
}

{
auto it = options.find("ncurses_buflist_show");
m_buflist_show = it != options.end() and
(it->value == "yes" or it->value == "true");
}

{
auto it = options.find("ncurses_buflist_separator");
m_buflist_separator = it != options.end() ? it->value : " ";
}

{
auto it = options.find("ncurses_set_title");
m_set_title = it == options.end() or
Expand Down
6 changes: 6 additions & 0 deletions src/ncurses_ui.hh
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ public:
const DisplayLine& mode_line,
const Face& default_face) override;

void draw_buflist(const DisplayLine& buflist,
const Face& default_face) override;

void menu_show(ConstArrayView<DisplayLine> items,
DisplayCoord anchor, Face fg, Face bg,
MenuStyle style) override;
Expand Down Expand Up @@ -121,6 +124,9 @@ private:
OnKeyCallback m_on_key;

bool m_status_on_top = false;
bool m_buflist_show = false;
String m_buflist_separator = " ";

ConstArrayView<StringView> m_assistant;

void enable_mouse(bool enabled);
Expand Down
20 changes: 20 additions & 0 deletions src/remote.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ enum class MessageType : char
InfoHide,
Draw,
DrawStatus,
DrawBufList,
Refresh,
SetOptions,
Key
Expand Down Expand Up @@ -318,6 +319,9 @@ class RemoteUI : public UserInterface
const DisplayLine& mode_line,
const Face& default_face) override;

void draw_buflist(const DisplayLine& buflist,
const Face& default_face) override;

void refresh(bool force) override;

DisplayCoord dimensions() override { return m_dimensions; }
Expand Down Expand Up @@ -466,6 +470,15 @@ void RemoteUI::draw_status(const DisplayLine& status_line,
m_socket_watcher.events() |= FdEvents::Write;
}

void RemoteUI::draw_buflist(const DisplayLine& buflist,
const Face& default_face)
{
MsgWriter msg{m_send_buffer, MessageType::DrawBufList};
msg.write(buflist);
msg.write(default_face);
m_socket_watcher.events() |= FdEvents::Write;
}

void RemoteUI::refresh(bool force)
{
MsgWriter msg{m_send_buffer, MessageType::Refresh};
Expand Down Expand Up @@ -601,6 +614,13 @@ RemoteClient::RemoteClient(StringView session, std::unique_ptr<UserInterface>&&
m_ui->draw_status(status_line, mode_line, default_face);
break;
}
case MessageType::DrawBufList:
{
auto buflist = reader.read<DisplayLine>();
auto default_face = reader.read<Face>();
m_ui->draw_buflist(buflist, default_face);
break;
}
case MessageType::Refresh:
m_ui->refresh(reader.read<bool>());
break;
Expand Down
3 changes: 3 additions & 0 deletions src/user_interface.hh
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ public:
const DisplayLine& mode_line,
const Face& default_face) = 0;

virtual void draw_buflist(const DisplayLine& buflist,
const Face& default_face) = 0;

virtual DisplayCoord dimensions() = 0;

virtual void refresh(bool force) = 0;
Expand Down

0 comments on commit 3986d18

Please sign in to comment.