mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-16 14:16:09 -06:00
219 lines
4.9 KiB
C++
219 lines
4.9 KiB
C++
#include "CodeEditor.h"
|
|
|
|
namespace Upp {
|
|
|
|
PythonSyntax::PythonSyntax() {}
|
|
|
|
void PythonSyntax::Highlight(const wchar *start, const wchar *end, HighlightOutput& hls, CodeEditor *editor, int line, int64 pos)
|
|
{
|
|
InitKeywords();
|
|
|
|
bool isComment = false;
|
|
bool isStr = false;
|
|
char strOpening;
|
|
|
|
const wchar* p = start;
|
|
while(p < end) {
|
|
if((*p == '#' || isComment) && !isStr) {
|
|
isComment = true;
|
|
hls.Put(hl_style[INK_COMMENT]);
|
|
}
|
|
else
|
|
if(*p == '\'' || *p == '\"' || isStr) {
|
|
hls.Put(hl_style[INK_CONST_STRING]);
|
|
if((*p == '\'' || *p == '\"') && p - 1 != start && *(p - 1) != '\\')
|
|
if (!isStr || strOpening == *p) {
|
|
isStr = !isStr;
|
|
strOpening = (char)*p;
|
|
}
|
|
}
|
|
else
|
|
if(IsSeparator(p) || p == start) {
|
|
WString w;
|
|
bool isW = false;
|
|
const wchar* bp = (p == start && !IsSeparator(p)) ? p : p + 1;
|
|
while (bp != end && !IsSeparator(bp))
|
|
w += *bp++;
|
|
|
|
bool isPutted = false;
|
|
if(IsSeparator(p)) {
|
|
hls.Put(hl_style[INK_NORMAL]);
|
|
isPutted = true;
|
|
}
|
|
if(IsKeyword(w)) {
|
|
hls.Put(w.GetLength(), hl_style[INK_KEYWORD]);
|
|
isW = true;
|
|
}
|
|
else
|
|
if(IsSpecialVar(w)) {
|
|
hls.Put(w.GetLength(), hl_style[INK_UPP]);
|
|
isW = true;
|
|
}
|
|
else
|
|
if(IsNumber(w)) {
|
|
hls.Put(w.GetLength(), hl_style[INK_CONST_INT]);
|
|
isW = true;
|
|
}
|
|
|
|
if(isW) {
|
|
p += w.GetLength() - (isPutted ? 0 : 1);
|
|
}
|
|
}
|
|
else
|
|
hls.Put(hl_style[INK_NORMAL]);
|
|
|
|
p++;
|
|
}
|
|
}
|
|
|
|
void PythonSyntax::IndentInsert(CodeEditor& editor, int chr, int count)
|
|
{
|
|
if(chr == '\n') {
|
|
while(count--) {
|
|
WString cursorLine = editor.GetWLine(editor.GetCursorLine());
|
|
editor.InsertChar('\n', 1);
|
|
|
|
Identation::Type idType = FindIdentationType(editor, cursorLine);
|
|
char idChar = GetIdentationByType(idType);
|
|
int mult = 1;
|
|
if(idType == Identation::Space)
|
|
mult = CalculateSpaceIndetationSize(editor);
|
|
if(LineHasColon(cursorLine))
|
|
editor.InsertChar(idChar, mult);
|
|
editor.InsertChar(idChar, CalculateLineIndetations(cursorLine, idType));
|
|
}
|
|
}
|
|
if(count > 0)
|
|
editor.InsertChar(chr, count);
|
|
}
|
|
|
|
bool PythonSyntax::IsSeparator(const wchar* c)
|
|
{
|
|
return *c == ' ' || *c == ':' || *c == ',' || *c == '.' || *c == '('
|
|
|| *c == ')' || *c == '[' || *c == ']' || *c == '{' || *c == '}'
|
|
|| *c == '\t';
|
|
}
|
|
|
|
bool PythonSyntax::IsKeyword(const WString& w)
|
|
{
|
|
return keywords.Find(w.ToString()) > -1;
|
|
}
|
|
|
|
bool PythonSyntax::IsSpecialVar(const WString& w)
|
|
{
|
|
return specialVars.Find(w.ToString()) > -1;
|
|
}
|
|
|
|
bool PythonSyntax::IsNumber(const WString& w)
|
|
{
|
|
RegExp exp("^-?[0-9]+$");
|
|
return exp.Match(w.ToString());
|
|
}
|
|
|
|
void PythonSyntax::InitKeywords()
|
|
{
|
|
static const char* pythonKeywords[] = {
|
|
"and", "as", "assert", "break", "class", "continue", "def",
|
|
"del", "elif", "else", "except", "finally", "for",
|
|
"from", "global", "if", "import", "in", "is", "lambda",
|
|
"not", "or", "pass", "raise", "return", "try",
|
|
"while", "with", "yield",
|
|
"None", "True", "False",
|
|
NULL
|
|
};
|
|
static const char* pythonSpecialVars[] = {
|
|
"self", "NotImplemented", "Ellipsis", "__debug__", "__file__", "__name__",
|
|
NULL
|
|
};
|
|
|
|
LoadSyntax(pythonKeywords, pythonSpecialVars);
|
|
}
|
|
|
|
void PythonSyntax::LoadSyntax(const char* keywordsArray[], const char* specialVarsArray[])
|
|
{
|
|
keywords.Clear();
|
|
while(*keywordsArray)
|
|
keywords.Add(*keywordsArray++);
|
|
|
|
specialVars.Clear();
|
|
while(*specialVarsArray)
|
|
specialVars.Add(*specialVarsArray++);
|
|
}
|
|
|
|
bool PythonSyntax::LineHasColon(const WString& line)
|
|
{
|
|
for(int i = line.GetLength() - 1; i >= 0; i--) {
|
|
if(line[i] == ':')
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int PythonSyntax::CalculateLineIndetations(const WString& line, Identation::Type type)
|
|
{
|
|
int count = 0;
|
|
for(int i = 0; i < line.GetLength(); i++) {
|
|
if(type == Identation::Tab && line[i] == '\t')
|
|
count++;
|
|
else
|
|
if(type == Identation::Space && line[i] == ' ')
|
|
count++;
|
|
else
|
|
break;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
PythonSyntax::Identation::Type PythonSyntax::FindIdentationType(CodeEditor& editor, const WString& line)
|
|
{
|
|
Identation::Type type = Identation::Unknown;
|
|
if(line.StartsWith("\t"))
|
|
type = Identation::Tab;
|
|
else
|
|
if(line.StartsWith(" "))
|
|
type = Identation::Space;
|
|
else {
|
|
for(int i = 0; i < editor.GetLineCount(); i++) {
|
|
WString cLine = editor.GetWLine(i);
|
|
if(cLine.StartsWith("\t")) {
|
|
type = Identation::Tab;
|
|
break;
|
|
}
|
|
else
|
|
if(cLine.StartsWith(" ")) {
|
|
type = Identation::Space;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return type;
|
|
}
|
|
|
|
int PythonSyntax::CalculateSpaceIndetationSize(CodeEditor& editor)
|
|
{
|
|
int current = 0;
|
|
for(int i = 0; i < editor.GetLineCount(); i++) {
|
|
WString line = editor.GetWLine(i);
|
|
for(int j = 0; j < line.GetLength(); j++) {
|
|
if(line[j] == ' ')
|
|
current++;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if(current > 0)
|
|
break;
|
|
}
|
|
|
|
// TODO: 4 is magic numer - try to find the way to get this number from ide constants
|
|
return current > 0 ? current : 4;
|
|
}
|
|
|
|
char PythonSyntax::GetIdentationByType(Identation::Type type)
|
|
{
|
|
if(type == Identation::Space)
|
|
return ' ';
|
|
return '\t';
|
|
}
|
|
|
|
}
|