~kiwec/ke

78c9c27553daf8c35b474c75eefec53e1ef3b9a8 — Wolf Clément 3 years ago c94cbb6
Reenable syntax highlighting
M src/Buffer.cpp => src/Buffer.cpp +1 -1
@@ 287,7 287,7 @@ void Buffer::insert(const wchar_t c, bool log_events) {
		}

		// Make sure we have a correct start_commented on the new line
		// Syntax::MarkStartCommented(current_line()); TODO
		Syntax::mark_start_commented(current_line());

		// Auto-indent
		if(next_indent > 0) {

M src/Line.cpp => src/Line.cpp +6 -4
@@ 6,6 6,11 @@
#include <cmath>

void Line::calc_size() {
  if(m_doc == nullptr) {
    m_size = 0;
    return;
  }
  
	auto ptr = begin();
	for(m_size = 0; ptr[m_size] != L'\n' && ptr[m_size] != L'\0'; m_size++);
}


@@ 105,11 110,8 @@ void Line::printFrom(uint start, uint x, uint y, uint bg) const {
	uint c = 0;
	uint8_t syntax_color;
	auto text = begin();
	uint max_syntax_index = length() - 1;
	for(uint i = 0; i < length(); i++) {
		// Fallback color in case syntax is not initialized
		if(i > max_syntax_index) syntax_color = TextColor::DEFAULT_COLOR;
		else syntax_color = syntax()[i];
		syntax_color = syntax()[i];

		if(text[i] == L'\t') {
			if(c >= start) {

M src/Line.hpp => src/Line.hpp +1 -1
@@ 10,7 10,7 @@ using uint = uint32_t;
/// Line objects are temporary and should NOT be stored
/// Any modification to the linked Data would break the class
class Line {
private:
protected:
	Text* m_doc;

	/// Line start in document

M src/Syntax.cpp => src/Syntax.cpp +159 -158
@@ 5,51 5,51 @@
#include "Syntax.hpp"

static const std::wstring operators[] = {
    L"auto",
    L"bool",
    L"break",
    L"case",
	L"catch",
    L"class",
    L"continue",
    L"const",
    L"constexpr",
    L"decltype",
    L"default",
    L"delete",
    L"do",
    L"double",
    L"else",
    L"false",
    L"float",
    L"for",
    L"if",
    L"inline",
    L"int",
    L"long",
    L"namespace",
    L"new",
	L"noexcept",
    L"nullptr",
	L"override",
    L"private",
    L"protected",
    L"public",
    L"return",
    L"short",
    L"sizeof",
    L"static",
	L"struct",
    L"switch",
    L"this",
	L"throw",
    L"true",
	L"try",
    L"unsigned",
	L"virtual",
    L"void",
    L"wchar_t",
    L"while",
  L"auto",
  L"bool",
  L"break",
  L"case",
  L"catch",
  L"class",
  L"continue",
  L"const",
  L"constexpr",
  L"decltype",
  L"default",
  L"delete",
  L"do",
  L"double",
  L"else",
  L"false",
  L"float",
  L"for",
  L"if",
  L"inline",
  L"int",
  L"long",
  L"namespace",
  L"new",
  L"noexcept",
  L"nullptr",
  L"override",
  L"private",
  L"protected",
  L"public",
  L"return",
  L"short",
  L"sizeof",
  L"static",
  L"struct",
  L"switch",
  L"this",
  L"throw",
  L"true",
  L"try",
  L"unsigned",
  L"virtual",
  L"void",
  L"wchar_t",
  L"while",
};

static constexpr uint operators_size = std::extent<decltype(operators)>::value;


@@ 71,36 71,62 @@ bool isAlphaNum(wchar_t c) {
void Syntax::prepare(Line line) {
	auto syntax = line.syntax();
	for(uint i = 0; i < line.length(); i++) {
		syntax[i] = 15;
		syntax[i] = DEFAULT_COLOR;
	}
}

std::vector<Section> Syntax::getSections(Line line, wchar_t delimstart, wchar_t delimend) {
	std::vector<Section> sections;

#if 0
	auto start = std::string::npos;
	for(uint i = 0; i < str.size(); i++) {
		// Ignore escaped char
		if(str[i] == '\\') {
			i++;
			continue;
		}

		if(start == std::string::npos) {
			if(str[i] == delimstart) {
				start = i;
			}
		} else {
			if(str[i] == delimend) {
				sections.push_back({ (uint)start, i });
				start = std::string::npos;
			}
		}
	}
#endif
std::vector<Section> Syntax::get_inline_matches(Line line, std::wstring match) {
  std::vector<Section> sections;
  auto match_length = match.length();
  
  auto start = std::string::npos;
  for(uint i = 0; i < line.length(); i++) {
    auto len = start == std::string::npos ? 0 : i - start;
    
    if(line[i] == match[len]) {
      if(start == std::string::npos) {
        start = i;
      }
      len++;
      if(len == match_length) {
        sections.push_back({ (uint)start, i + 1 });
        start = std::string::npos;
      }
    } else {
      start = std::string::npos;
    }
  }
  
  return sections;
}

	return sections;
std::vector<Section> Syntax::get_inline_strings(Line line, wchar_t delimiter) {
  std::vector<Section> sections;
  
  auto start = std::string::npos;
  for(uint i = 0; i < line.length(); i++) {
    // Ignore escaped characters
    if(line[i] == L'\\') {
      i++;
      if(line[i] == L'\\') {
        i++;
      }
      continue;
    }
    
    if(start == std::string::npos) {
      if(line[i] == delimiter) {
        start = i;
      }
    } else {
      if(line[i] == delimiter) {
        sections.push_back({ (uint)start, i });
        start = std::string::npos;
      }
    }
  }
  
  return sections;
}

void Syntax::markPreprocessor(Line line) {


@@ 118,78 144,65 @@ void Syntax::markPreprocessor(Line line) {
}

void Syntax::markComments(Line line) {
#if 0
	const auto str = line.begin();

	// Mark line comments
	unsigned long pos = 0;
	auto max = std::string::npos;
	while(pos != std::string::npos) {
		pos = str.find(L"//", pos);
		if(pos == std::string::npos) break;

		// Ignore comment in a string
		if(line->syntax[pos] == STRING_COLOR) {
			pos += 2;
		} else {
			// We still search for zone comments before
			// the start of the line comment
			max = pos;

			// Color until end of line
			while(pos < str.size()) {
				line->syntax[pos] = COMMENT_COLOR;
				pos++;
			}
		}
	}

	// Mark zone comments
	bool commenting = line->start_commented;
	pos = 0;
  auto line_comment_matches = Syntax::get_inline_matches(line, L"//");
  for(auto& match : line_comment_matches) {
    // Ignore comment in a string
    if(line.syntax()[match.start] == STRING_COLOR) continue;
    
    for(uint i = match.start; i < line.length(); i++) {
      line.syntax()[i] = COMMENT_COLOR;
    }
    
    break;
  }
  
  // Storing start_commented in previous line's newline syntax location
  bool commenting = line.is_first() ? false : line.syntax()[-1] == COMMENT_COLOR;
	auto pos = 0;
  auto max = line.length();
  auto starts = Syntax::get_inline_matches(line, L"/*");
  auto ends = Syntax::get_inline_matches(line, L"*/");
	while(pos < max) {
		if(commenting) {
			auto end = str.find(L"*/", pos);
			if(end == std::string::npos) {
				// Color until end of line
				while(pos < str.size()) {
					line->syntax[pos] = COMMENT_COLOR;
					pos++;
				}
				pos = std::string::npos; // break
			} else {
				// Color until end of comment zone
				while(pos < end + 2) {
					line->syntax[pos] = COMMENT_COLOR;
					pos++;
				}
				commenting = false;
			}
		} else {
			pos = str.find(L"/*", pos);
			if(pos != std::string::npos) {
				if(line->syntax[pos] == DEFAULT_COLOR)
					commenting = true;
				else
					pos += 2;
			}
		}
    if(commenting) {
      line.syntax()[pos] = COMMENT_COLOR;
    
      for(auto& end : ends) {
        if(end.end == pos) {
          if(line.syntax()[end.end] == STRING_COLOR) continue;
          commenting = false;
          break;
        }
      }
    } else {
      for(auto& start : starts) {
        if(start.start == pos) {
          if(line.syntax()[start.start] == STRING_COLOR) continue;
          commenting = true;
          line.syntax()[pos] = COMMENT_COLOR;
          line.syntax()[pos + 1] = COMMENT_COLOR;
          pos++;
          break;
        }
      }
    }
    
    pos++;
	}

	if(!line->is_last()) {
	if(!line.is_last()) {
		if(commenting) {
			if(!line->next()->start_commented) {
				line->next()->start_commented = true;
				Syntax::update(line->next());
			if(line.syntax()[max] != COMMENT_COLOR) {
        line.syntax()[max] = COMMENT_COLOR;
				Syntax::update(line.next());
			}
		} else {
			if(line->next()->start_commented) {
				line->next()->start_commented = false;
				Syntax::update(line->next());
			if(line.syntax()[max] == COMMENT_COLOR) {
        line.syntax()[max] = DEFAULT_COLOR;
				Syntax::update(line.next());
			}
		}
	}
#endif
}

void Syntax::markNumbers(Line line) {


@@ 203,7 216,7 @@ void Syntax::markNumbers(Line line) {
}

void Syntax::markChars(Line line) {
	auto chars = Syntax::getSections(line, L'\'', L'\'');
	auto chars = Syntax::get_inline_strings(line, L'\'');
	auto syntax = line.syntax();
	for(auto& sec : chars) {
		for(uint i = sec.start; i <= sec.end; i++) {


@@ 213,7 226,7 @@ void Syntax::markChars(Line line) {
}

void Syntax::markStrings(Line line) {
	auto strings = Syntax::getSections(line, L'"', L'"');
	auto strings = Syntax::get_inline_strings(line, L'"');
	auto syntax = line.syntax();
	for(auto& sec : strings) {
		for(uint i = sec.start; i <= sec.end; i++) {


@@ 225,25 238,16 @@ void Syntax::markStrings(Line line) {
void Syntax::markOperators(Line line) {
	const auto str = line.begin();

#if 0
	for(uint i = 0; i < operators_size; i++) {
		auto pos = str.find(operators[i]);
		if(pos == std::string::npos)
			continue;
		if(line->syntax[pos] != DEFAULT_COLOR)
			continue;
		if(pos != 0 && isAlphaNum(str[pos - 1]))
			continue;

		auto opsize = operators[i].size();
		if(pos + opsize < str.size() && isAlphaNum(str[pos + opsize]))
			continue;

		for(uint j = 0; j < operators[i].size(); j++) {
			line->syntax[pos + j] = 11;
		}
    auto line_operator_matches = Syntax::get_inline_matches(line, operators[i]);
    for(auto& match : line_operator_matches) {
      if(line.syntax()[match.start] != DEFAULT_COLOR) continue;
      if(match.start != 0 && isAlphaNum(line[match.start - 1])) continue;
      for(uint j = match.start; j < match.end; j++) {
        line.syntax()[j] = OPERATOR_COLOR;
      }
    }
	}
#endif
}

void Syntax::markSpecial(Line line) {


@@ 259,17 263,14 @@ void Syntax::markSpecial(Line line) {
#endif
}

/*
void Syntax::MarkStartCommented(Line* line) {
	if(line->is_first()) {
		line->start_commented = false;
void Syntax::mark_start_commented(Line line) {
	if(line.is_first()) {
		return;
	}

	// Updates prev line's comment syntax and this line's start_commented
	markComments(line->prev());
	markComments(line.prev());
}
*/

void Syntax::update(Text& text) {
	Line line = text.get_line(1);

M src/Syntax.hpp => src/Syntax.hpp +6 -3
@@ 1,5 1,6 @@
#pragma once
#include <stdint.h>
#include <string>
#include <vector>

using syntax_t = uint8_t;


@@ 11,6 12,7 @@ enum TextColor {
	CHAR_COLOR = 1,
	COMMENT_COLOR = 2,
	STRING_COLOR = 6,
  OPERATOR_COLOR = 11,
	DEFAULT_COLOR = 15,
};



@@ 26,12 28,13 @@ private:
	static void markOperators(Line line);
	static void markSpecial(Line line);

	static std::vector<Section> getSections(Line line, wchar_t delimstart, wchar_t delimend);

public:
	// Marks the line's start_commented bool based on
	// previous's line start_commented and text
	// static void MarkStartCommented(Line line);
  static void mark_start_commented(Line line);

  static std::vector<Section> get_inline_matches(Line line, std::wstring match);
	static std::vector<Section> get_inline_strings(Line line, wchar_t delimiter);

	static void update(Text& text);
	static void update(Line line);

M test/Document.hpp => test/Document.hpp +1 -2
@@ 1,6 1,5 @@
#pragma once
#define TEST_NO_MAIN
#include "acutest.h"
#include "TestUtils.hpp"
#include "../src/Document.hpp"

void test_inserted_text();

M test/Line.hpp => test/Line.hpp +1 -2
@@ 1,6 1,5 @@
#pragma once
#define TEST_NO_MAIN
#include "acutest.h"
#include "TestUtils.hpp"
#include "../src/Line.hpp"

void test_line_insert();

A test/Syntax.cpp => test/Syntax.cpp +21 -0
@@ 0,0 1,21 @@
#include "Syntax.hpp"

#include "../src/Document.hpp"
#include "../src/Line.hpp"
#include "../src/Section.hpp"

#include <stdio.h>

void test_syntax_inline_matches() {
  {
    TestLine line(L"there are three spaces");
    auto matches = Syntax::get_inline_matches(line, L" ");
    TEST_CHECK(matches.size() == 3);
  }
  
  {
    TestLine line(L"// multichar // matches");
    auto matches = Syntax::get_inline_matches(line, L"//");
    TEST_CHECK(matches.size() == 2);
  }
}

A test/Syntax.hpp => test/Syntax.hpp +5 -0
@@ 0,0 1,5 @@
#pragma once
#include "TestUtils.hpp"
#include "../src/Syntax.hpp"

void test_syntax_inline_matches();

A test/TestUtils.hpp => test/TestUtils.hpp +23 -0
@@ 0,0 1,23 @@
#pragma once

#include <string>

#define TEST_NO_MAIN
#include "acutest.h"

#include "../src/Document.hpp"
#include "../src/Line.hpp"

/// TestLine doesn't require a Text document to be created beforehand'
class TestLine : public Line {
public:
  TestLine(std::wstring text) : Line(nullptr, 0, 1) {
    m_doc = new Text();
    m_doc->insert(text.c_str(), text.length(), 0);
    calc_size();
  }
  
  ~TestLine() {
    delete m_doc;
  }
};

M test/tests.cpp => test/tests.cpp +4 -0
@@ 2,6 2,7 @@

#include "Document.hpp"
#include "Line.hpp"
#include "Syntax.hpp"

TEST_LIST = {
	// Document.hpp


@@ 13,6 14,9 @@ TEST_LIST = {
	{ "line-insert", test_line_insert },
	{ "line-count", test_line_count },
	{ "prev-next-line", test_prev_next_line },
  
  // Syntax.hpp
	{ "syntax-inline-matches", test_syntax_inline_matches },

	{ NULL, NULL }
};