~kiwec/ke

2133c126a17a4627ffb76143c19c287e9c272749 — Wolf Clément 3 years ago 8423969
Add error, info and success messages
5 files changed, 120 insertions(+), 41 deletions(-)

M src/Editor.cc
M src/Editor.h
R src/{StatusBar.cc => Status.cc}
A src/Status.h
D src/StatusBar.h
M src/Editor.cc => src/Editor.cc +32 -17
@@ 4,7 4,7 @@
#include "Editor.h"
#include "Prompt.h"
#include "Gutter.h"
#include "StatusBar.h"
#include "Status.h"

void Editor::draw() {
	tb_clear();


@@ 19,28 19,35 @@ void Editor::draw() {
}

bool Editor::handle_key(tb_event* ev) {
	m_status.handle_key(ev);

	switch(ev->key) {
	case TB_KEY_CTRL_G:
		m_status.prompt = std::make_unique<Prompt>(L"Go to line : ", [&buf = *m_buf](auto answer) {
		m_status.prompt = std::make_unique<Prompt>(L"Go to line : ", [this](auto answer) {
			int line = -1;

			try {
				line = std::stoi(answer);
				if(line < 0) throw;
			} catch(std::exception& e) {
				// TODO show error
				m_status.set_msg(L"Invalid line number", StatusType::ERROR);
				return;
			}

			if(line > 0) {
				buf.move_to(line);
			}
			m_buf->move_to(line);
		});
		return true;
	case TB_KEY_CTRL_F:
		m_status.prompt = std::make_unique<Prompt>(L"Find : ", [&buf = *m_buf](auto answer) {
			if(answer == L"") return;
			auto result = buf.m_text.search(answer);
			buf.move_to(result.first, result.second);
			// TODO show no matches
		m_status.prompt = std::make_unique<Prompt>(L"Find : ", [this](auto answer) {
			// TODO highlight matches
			if(*answer == L'\0') {
				// TODO jump to next match instead
				m_status.set_msg(L"No text given, not searching.", StatusType::INFO);
				return;
			}

			auto result = m_buf->m_text.search(answer);
			m_buf->move_to(result.first, result.second);
			// TODO show more information (no matches / match X of X)
		});
		return true;
	case TB_KEY_CTRL_Q:


@@ 54,19 61,27 @@ bool Editor::handle_key(tb_event* ev) {
		return true;
	case TB_KEY_CTRL_O:
		m_status.prompt = std::make_unique<Prompt>(L"Open file : ", [this](auto answer) {
			if(answer == L"") return; // TODO show error
			if(*answer == L'\0') {
				m_status.set_msg(L"No filename given, not opening.", StatusType::INFO);
				return;
			}
			auto str = Convert::from_wide_string(answer);
			// TODO check if file can be opened
			open(str.get());
		});
		return true;
	case TB_KEY_CTRL_S:
		// Ctrl-Alt-S
		if(ev->mod == TB_MOD_ALT || m_buf->filename == "") {
			m_status.prompt = std::make_unique<Prompt>(L"Save as : ", [&buf = *m_buf](auto answer) {
				if(answer == L"") return; // TODO show error
			m_status.prompt = std::make_unique<Prompt>(L"Save as : ", [this](auto answer) {
				if(*answer == L'\0') {
					m_status.set_msg(L"No filename given, not saving.", StatusType::ERROR);
					return;
				}
				auto str = Convert::from_wide_string(answer);
				buf.filename = str.get();
				buf.save();
				m_buf->filename = str.get();
				// TODO if file was saved successfully
				m_buf->save();
			});

			auto wstr = Convert::to_wide_string(m_buf->filename.c_str());

M src/Editor.h => src/Editor.h +2 -2
@@ 1,13 1,13 @@
#pragma once
#include <memory>
#include "Buffer.h"
#include "StatusBar.h"
#include "Status.h"

// TODO remove shared_ptr
class Editor : public InputHandler {
private:
	std::shared_ptr<Buffer> m_buf;
	StatusBar m_status;
	Status m_status;
	
public:
	void draw();

R src/StatusBar.cc => src/Status.cc +52 -5
@@ 1,13 1,16 @@
#include "StatusBar.h"
#include "Status.h"
#include "Buffer.h"
#include "Conversion.h"
#include "Editor.h"
#include "File.h"
#include "Line.h"
#include <sstream>
#include <stdlib.h>
#include <termbox.h>

void StatusBar::draw(Buffer& buf) {
void Status::draw(Buffer& buf) {
	int16_t fg = 232, bg = 220;

	// Text aligned to the left
	std::wostringstream left;
	// Filename


@@ 34,7 37,7 @@ void StatusBar::draw(Buffer& buf) {
	right << L"/" << buf.m_text.get_nb_lines();
	right << L" ";
	auto right_str = right.str();
	auto rwidth = right_str.size();
	int rwidth = right_str.size();

	// Yellow background
	for(int i = 0; i < tb_width(); i++) {


@@ 47,7 50,36 @@ void StatusBar::draw(Buffer& buf) {
	// Text
	Canvas::print(right_str.c_str(), tb_width() - rwidth, tb_height() - 1, fg, bg);

	// Prompt
	// Print message if there is one
	if(_msg != nullptr) {
		// Set message colors
		switch(_type) {
			case StatusType::DEFAULT:
			case StatusType::INFO:
				break;
			case StatusType::ERROR:
				bg = 9;
				fg = 15;
				break;
			case StatusType::SUCCESS:
				bg = 2;
				fg = 15;
				break;
/*
			case StatusType::PROMPT:
				bg = 0;
				fg = 234;
				break;
*/
		}

		// Draw the message
		for(int i = 0; i < tb_width() - rwidth; i++) {
			tb_change_cell(i, tb_height() - 1, ' ', fg, bg);
		}
		Canvas::print(_msg, 1, tb_height() - 1, fg, bg);
	}

	if(prompt != nullptr) {
		if(prompt->is_prompting()) {
			prompt->draw(rwidth);


@@ 57,7 89,22 @@ void StatusBar::draw(Buffer& buf) {
	}
}

int StatusBar::height() {
int Status::height() {
	// Could be higher in the future
	return 1;
}

void Status::handle_key(tb_event* ev) {
	if(_msg == nullptr) return;
	// if(_type == StatusType::PROMPT) return;

	// Remove currently displayed msg
	free(_msg);
	_msg = nullptr;
}

void Status::set_msg(const wchar_t* msg, StatusType type) {
	if(_msg != nullptr) free(_msg);
	_msg = wcsdup(msg);
	_type = type;
}

A src/Status.h => src/Status.h +34 -0
@@ 0,0 1,34 @@
#pragma once
#include <memory>
#include <termbox.h>
#include "Prompt.h"

class Buffer;

enum class StatusType {
	DEFAULT,
	INFO,
	ERROR,
	SUCCESS,
//	PROMPT,
};

class Status {
private:
	wchar_t* _msg = nullptr;
	StatusType _type;

public:
	std::unique_ptr<Prompt> prompt = nullptr;

	~Status() {
		if(_msg != nullptr) {
			free(_msg);
		}
	}

	void draw(Buffer& buf);
	int height();
	void handle_key(tb_event* ev);
	void set_msg(const wchar_t* msg, StatusType type);
};

D src/StatusBar.h => src/StatusBar.h +0 -17
@@ 1,17 0,0 @@
#pragma once
#include <memory>
#include "Prompt.h"

class Buffer;

class StatusBar {
private:
	const int16_t fg = 232;
	const int16_t bg = 220;

public:
	std::unique_ptr<Prompt> prompt = nullptr;

	void draw(Buffer& buf);
	int height();
};