diff --git a/uppsrc/CodeEditor/CInit.cpp b/uppsrc/CodeEditor/CInit.cpp index 4035ff139..d3a37c66c 100644 --- a/uppsrc/CodeEditor/CInit.cpp +++ b/uppsrc/CodeEditor/CInit.cpp @@ -344,7 +344,7 @@ void CSyntax::InitKeywords() int CSyntax::LoadSyntax(const char *keywords[], const char *names[]) // Changed { - Index& key = keyword.Add() ; + Index& key = keyword.Add(); while(*keywords) key.Add(*keywords++); Index & nam = name.Add(); diff --git a/uppsrc/CodeEditor/CRegister.icpp b/uppsrc/CodeEditor/CRegister.icpp index 25bfb5c2f..c4e4c634b 100644 --- a/uppsrc/CodeEditor/CRegister.icpp +++ b/uppsrc/CodeEditor/CRegister.icpp @@ -13,16 +13,21 @@ void RegisterCSyntax(const char *id, int kind, EditorSyntax::Register(id, callback1(CreateCSyntax, kind), exts, description); } -void CreateTagSyntax(One& e, bool html, bool witz) -{ - e.Create().Html(html).Witz(witz); -} - void CreateDiffSyntax(One& e) { e.Create(); } +void CreatePythonSyntax(One& e) +{ + e.Create(); +} + +void CreateTagSyntax(One& e, bool html, bool witz) +{ + e.Create().Html(html).Witz(witz); +} + void CreateLogSyntax(One& e) { e.Create(); @@ -46,12 +51,14 @@ INITBLOCK RegisterCSyntax("calc", CSyntax::HIGHLIGHT_CALC, "", ""); RegisterCSyntax("php", CSyntax::HIGHLIGHT_PHP, "*.php", "PHP"); + EditorSyntax::Register("diff", callback(CreateDiffSyntax), "*.diff *.patch", "Diff"); + + EditorSyntax::Register("python", callback(CreatePythonSyntax), "*.py, *.pyc, *.pyd, *.pyo, *.pyw, *.pyz", "Python"); + EditorSyntax::Register("xml", callback2(CreateTagSyntax, false, false), "*.xml *.xsd", "XML (.xml)"); EditorSyntax::Register("html", callback2(CreateTagSyntax, true, false), "*.html *.htm", "HTML (.html)"); EditorSyntax::Register("witz", callback2(CreateTagSyntax, true, true), "*.witz", "Skylark templates (.witz)"); - EditorSyntax::Register("diff", callback(CreateDiffSyntax), "*.diff *.patch", "Diff"); - EditorSyntax::Register("log", callback(CreateLogSyntax), "*.log", "Log (*.log)"); } diff --git a/uppsrc/CodeEditor/CodeEditor.h b/uppsrc/CodeEditor/CodeEditor.h index f9255ce9f..9420a36e3 100644 --- a/uppsrc/CodeEditor/CodeEditor.h +++ b/uppsrc/CodeEditor/CodeEditor.h @@ -175,6 +175,7 @@ struct FindReplaceDlg : FrameBottom< WithIDEFindReplaceLayout > { #include "DiffSyntax.h" #include "TagSyntax.h" #include "LogSyntax.h" +#include "PythonSyntax.h" class CodeEditor : public LineEdit, public HighlightSetup diff --git a/uppsrc/CodeEditor/CodeEditor.upp b/uppsrc/CodeEditor/CodeEditor.upp index 95516de98..dc6f0ced1 100644 --- a/uppsrc/CodeEditor/CodeEditor.upp +++ b/uppsrc/CodeEditor/CodeEditor.upp @@ -28,6 +28,9 @@ file TagSyntax readonly separator, TagSyntax.h, TagSyntax.cpp, + PythonSyntax readonly separator, + PythonSyntax.cpp, + PythonSyntax.h, LogSyntax readonly separator, LogSyntax.h, LogSyntax.cpp, diff --git a/uppsrc/CodeEditor/PythonSyntax.cpp b/uppsrc/CodeEditor/PythonSyntax.cpp new file mode 100644 index 000000000..2d7f20244 --- /dev/null +++ b/uppsrc/CodeEditor/PythonSyntax.cpp @@ -0,0 +1,219 @@ +#include "CodeEditor.h" + +NAMESPACE_UPP + +PythonSyntax::PythonSyntax() {} + +void PythonSyntax::Highlight(const wchar *start, const wchar *end, HighlightOutput& hls, CodeEditor *editor, int line, int 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::None; + 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'; +} + +END_UPP_NAMESPACE diff --git a/uppsrc/CodeEditor/PythonSyntax.h b/uppsrc/CodeEditor/PythonSyntax.h new file mode 100644 index 000000000..e6b1d9c7e --- /dev/null +++ b/uppsrc/CodeEditor/PythonSyntax.h @@ -0,0 +1,37 @@ +class PythonSyntax : public EditorSyntax { +private: + struct Identation { + enum Type { + Tab = 0, + Space, + None + }; + }; + +public: + PythonSyntax(); + + virtual void Highlight(const wchar *start, const wchar *end, HighlightOutput& hls, + CodeEditor *editor, int line, int pos); + virtual void IndentInsert(CodeEditor& e, int chr, int count); + +private: + bool IsSeparator(const wchar* c); + + bool IsKeyword(const WString& w); + bool IsSpecialVar(const WString& w); + bool IsNumber(const WString& w); + + void InitKeywords(); + void LoadSyntax(const char* keywordsArray[], const char* specialVarsArray[]); + + bool LineHasColon(const WString& line); + int CalculateLineIndetations(const WString& line, Identation::Type type); + int CalculateSpaceIndetationSize(CodeEditor& editor); + Identation::Type FindIdentationType(CodeEditor& editor, const WString& line); + char GetIdentationByType(Identation::Type type); + +private: + Index keywords; + Index specialVars; +};