From b13b6659137166079f1d2947d70a00c4ee6092f3 Mon Sep 17 00:00:00 2001
From: Michael Ochmann <miko007@me.com>
Date: Mon, 6 Mar 2017 14:48:29 +0100
Subject: [PATCH] added syntax highlighting

---
 src/Editor.cpp          | 39 ++++++++++++++++++++++++++++++++++---
 src/Editor.hpp          |  2 +-
 src/Highlighter.cpp     | 43 +++++++++++++++++++++++++++++++++++++++++
 src/Highlighter.hpp     | 24 +++++++++++++++++++++++
 src/ncurses/ncurses.hpp | 21 ++++++++++++++++++--
 5 files changed, 123 insertions(+), 6 deletions(-)
 create mode 100644 src/Highlighter.cpp
 create mode 100644 src/Highlighter.hpp

diff --git a/src/Editor.cpp b/src/Editor.cpp
index ea248b9..93c7cae 100644
--- a/src/Editor.cpp
+++ b/src/Editor.cpp
@@ -1,4 +1,5 @@
 #include <Editor.hpp>
+#include <Highlighter.hpp>
 #include <fstream>
 #include <iostream>
 
@@ -154,6 +155,15 @@ namespace groove {
 						break;
 					default:
 						{
+							switch (car) {
+								case '{':
+								case '[':
+									this->buffer->at(this->y).insert(this->x, 1, car + 2);
+									break;
+								case '(':
+									this->buffer->at(this->y).insert(this->x, 1, car + 1);
+									break;
+							}
 							std::ofstream log("log");
 							log << car << std::endl;
 							this->buffer->at(this->y).insert(this->x, 1, char(car));
@@ -191,7 +201,30 @@ namespace groove {
 			}
 			else {
 				std::string line = /*std::to_string(i) + " | " +*/ this->buffer->at(i);
-				mvprintw(i - this->offset, 0, line.c_str());
+				Highlighter highlighter(line);
+				std::unordered_map<int, std::pair<int, ncurses::Colors>> hilist = highlighter.get();
+				int x = 0;
+				int found = -1;
+				int len = -1;
+				for (auto& car : line) {
+					if (hilist.find(x) != hilist.end()) {
+						found = x;
+						len = hilist.at(x).first;
+					}
+					if (found >= 0 && len >= 0) {
+						if (x >= found && x <= found + len - 1)
+							attron(COLOR_PAIR(hilist.at(found).second));
+						else if (x > found && x >= found + len) {
+							attron(COLOR_PAIR(ncurses::Colors::MAIN));
+							found = -1;
+							len = -1;
+						}
+					}
+					mvaddch(i - this->offset, x, car);
+					attron(COLOR_PAIR(ncurses::Colors::MAIN));
+					x++;
+				}
+				//mvprintw(i - this->offset, 0, line.c_str());
 			}
 			clrtoeol();
 		}
@@ -224,11 +257,11 @@ namespace groove {
 
 		status += std::string(COLS - status.length(), ' ');
 
-		attron(COLOR_PAIR(2));
+		attron(COLOR_PAIR(ncurses::Colors::STATUSBAR));
 		mvprintw(LINES-1, 0, status.c_str());
 
 		//clrtoeol();
-		attroff(COLOR_PAIR(2));
+		attroff(COLOR_PAIR(ncurses::Colors::STATUSBAR));
 	}
 
 }
\ No newline at end of file
diff --git a/src/Editor.hpp b/src/Editor.hpp
index f1f243f..fc853b7 100644
--- a/src/Editor.hpp
+++ b/src/Editor.hpp
@@ -2,7 +2,7 @@
 
 #include <memory>
 #include <Buffer.hpp>
-#include <ncurses.h>
+#include <ncurses/ncurses.hpp>
 
 namespace groove {
 
diff --git a/src/Highlighter.cpp b/src/Highlighter.cpp
new file mode 100644
index 0000000..739dc52
--- /dev/null
+++ b/src/Highlighter.cpp
@@ -0,0 +1,43 @@
+#include <regex>
+#include <Highlighter.hpp>
+#include <iostream>
+
+namespace groove {
+
+	std::vector<std::pair<std::regex, ncurses::Colors>> Highlighter::list = {
+			make_pair("([+-.<>,;=!:])", ncurses::Colors::CYAN),
+			make_pair("([\\{\\}\\[\\]\\(\\)])", ncurses::Colors::GREEN),
+			make_pair("(while|if|try|catch|void|this|char|bool|unsigned|long|short|int|return)\\*?", ncurses::Colors::MAGENTA),
+			make_pair("([a-zA-Z_][a-zA-Z_0-9]+)::", ncurses::Colors::GREEN),
+			make_pair("::([a-zA-Z_][a-zA-Z_0-9]+)", ncurses::Colors::CYAN),
+			make_pair("\\.([a-zA-Z_][a-zA-Z_0-9]+)", ncurses::Colors::CYAN),
+			make_pair("\\\".*\\\"", ncurses::Colors::ORANGE),
+			make_pair("/\\*.*\\*//*", ncurses::Colors::ORANGE),
+			make_pair("(//.*)", ncurses::Colors::ORANGE),
+			make_pair("(^#.*)", ncurses::Colors::ORANGE)
+	};
+
+	std::unordered_map<int, std::pair<int, ncurses::Colors>> groove::Highlighter::get() {
+		std::unordered_map<int, std::pair<int, ncurses::Colors>> list;
+
+		for (auto& keyword : Highlighter::list) {
+			try {
+				std::sregex_iterator next(this->line.begin(), this->line.end(), keyword.first);
+				std::sregex_iterator end;
+				while (next != end) {
+					std::smatch match = *next;
+					for (unsigned i = 0; i < match.size(); ++i) {
+						list.emplace(match.position(i), std::make_pair(match.length(i), keyword.second));
+					}
+					next++;
+				}
+			} catch (std::regex_error& e) {
+				// Syntax error in the regular expression
+			}
+		}
+
+		return list;
+
+	}
+
+}
diff --git a/src/Highlighter.hpp b/src/Highlighter.hpp
new file mode 100644
index 0000000..bebc66d
--- /dev/null
+++ b/src/Highlighter.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <string>
+#include <ncurses/ncurses.hpp>
+#include <vector>
+#include <unordered_map>
+#include <regex>
+
+namespace groove {
+
+	inline std::pair<std::regex, ncurses::Colors> make_pair(std::string regex, ncurses::Colors color) {
+		return std::make_pair(std::regex(regex), color);
+	};
+
+	class Highlighter {
+	private:
+		std::string line;
+		static std::vector<std::pair<std::regex, ncurses::Colors>> list;
+	public:
+		Highlighter(std::string line) : line(line) {}
+		std::unordered_map<int, std::pair<int, ncurses::Colors>> get();
+	};
+
+}
\ No newline at end of file
diff --git a/src/ncurses/ncurses.hpp b/src/ncurses/ncurses.hpp
index 0b7c407..4c4145d 100644
--- a/src/ncurses/ncurses.hpp
+++ b/src/ncurses/ncurses.hpp
@@ -13,6 +13,17 @@ namespace groove {
 					b(static_cast<short>(b * 0.255)) {}
 		};
 
+		enum Colors {
+			MAIN = 1,
+			STATUSBAR,
+			MAGENTA,
+			GREEN,
+			PURPLE,
+			ORANGE,
+			CYAN,
+			GREY
+		};
+
 		class ncurses {
 		public:
 			ncurses() {};
@@ -24,8 +35,14 @@ namespace groove {
 				keypad(stdscr, true);           // Enable special keys to be recorde
 
 				start_color();
-				init_pair(1, COLOR_WHITE, COLOR_BLACK);
-				init_pair(2, COLOR_WHITE, COLOR_MAGENTA);
+				init_pair(Colors::MAIN, COLOR_WHITE, COLOR_BLACK);
+				init_pair(Colors::STATUSBAR, COLOR_WHITE, COLOR_MAGENTA);
+				init_pair(Colors::MAGENTA, COLOR_MAGENTA, COLOR_BLACK);
+				init_pair(Colors::GREEN, COLOR_GREEN, COLOR_BLACK);
+				init_pair(Colors::GREY, COLOR_YELLOW, COLOR_BLACK);
+				init_pair(Colors::CYAN, COLOR_CYAN, COLOR_BLACK);
+				init_pair(Colors::ORANGE, COLOR_YELLOW, COLOR_BLACK);
+
 				if (can_change_color()) {
 					Color grey(39, 40, 34);
 					Color pink(255, 0, 103);