aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Editor.cxx21
-rw-r--r--src/Editor.h1
-rw-r--r--src/KeyMap.cxx1
-rw-r--r--src/KeyWords.cxx1
-rw-r--r--src/LexCSS.cxx234
-rw-r--r--src/LexHTML.cxx42
6 files changed, 284 insertions, 16 deletions
diff --git a/src/Editor.cxx b/src/Editor.cxx
index 76ba18565..2af278b19 100644
--- a/src/Editor.cxx
+++ b/src/Editor.cxx
@@ -3134,6 +3134,7 @@ void Editor::NotifyMacroRecord(unsigned int iMessage, unsigned long wParam, long
case SCI_LINECUT:
case SCI_LINEDELETE:
case SCI_LINETRANSPOSE:
+ case SCI_LINEDUPLICATE:
case SCI_LOWERCASE:
case SCI_UPPERCASE:
case SCI_LINESCROLLDOWN:
@@ -3234,6 +3235,22 @@ void Editor::LineTranspose() {
}
}
+void Editor::LineDuplicate() {
+ int line = pdoc->LineFromPosition(currentPos);
+ int start = pdoc->LineStart(line);
+ int end = pdoc->LineEnd(line);
+ char *thisLine = CopyRange(start, end);
+ const char *eol = "\n";
+ if (pdoc->eolMode == SC_EOL_CRLF) {
+ eol = "\r\n";
+ } else if (pdoc->eolMode == SC_EOL_CR) {
+ eol = "\r";
+ }
+ pdoc->InsertString(end, eol);
+ pdoc->InsertString(end + strlen(eol), thisLine, end - start);
+ delete []thisLine;
+}
+
void Editor::CancelModes() {}
void Editor::NewLine() {
@@ -3518,6 +3535,9 @@ int Editor::KeyCommand(unsigned int iMessage) {
case SCI_LINETRANSPOSE:
LineTranspose();
break;
+ case SCI_LINEDUPLICATE:
+ LineDuplicate();
+ break;
case SCI_LOWERCASE:
ChangeCaseOfSelection(false);
break;
@@ -5665,6 +5685,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
case SCI_LINECUT:
case SCI_LINEDELETE:
case SCI_LINETRANSPOSE:
+ case SCI_LINEDUPLICATE:
case SCI_LOWERCASE:
case SCI_UPPERCASE:
case SCI_LINESCROLLDOWN:
diff --git a/src/Editor.h b/src/Editor.h
index 3d99676ae..d4cbe50ff 100644
--- a/src/Editor.h
+++ b/src/Editor.h
@@ -404,6 +404,7 @@ protected: // ScintillaBase subclass needs access to much of Editor
void PageMove(int direction, bool extend=false);
void ChangeCaseOfSelection(bool makeUpperCase);
void LineTranspose();
+ void LineDuplicate();
virtual void CancelModes();
void NewLine();
void CursorUpOrDown(int direction, bool extend=false);
diff --git a/src/KeyMap.cxx b/src/KeyMap.cxx
index c91e6c6cc..4e580e8e6 100644
--- a/src/KeyMap.cxx
+++ b/src/KeyMap.cxx
@@ -127,6 +127,7 @@ const KeyToCommand KeyMap::MapDefault[] = {
{'L', SCI_CTRL, SCI_LINECUT},
{'L', SCI_CSHIFT, SCI_LINEDELETE},
{'T', SCI_CTRL, SCI_LINETRANSPOSE},
+ {'D', SCI_CTRL, SCI_LINEDUPLICATE},
{'U', SCI_CTRL, SCI_LOWERCASE},
{'U', SCI_CSHIFT, SCI_UPPERCASE},
{0,0,0},
diff --git a/src/KeyWords.cxx b/src/KeyWords.cxx
index d9682b606..6183916c6 100644
--- a/src/KeyWords.cxx
+++ b/src/KeyWords.cxx
@@ -151,6 +151,7 @@ int Scintilla_LinkLexers() {
LINK_LEXER(lmCPPNoCase);
LINK_LEXER(lmTCL);
LINK_LEXER(lmNncrontab);
+ LINK_LEXER(lmCss);
LINK_LEXER(lmEiffel);
LINK_LEXER(lmEiffelkw);
LINK_LEXER(lmFortran);
diff --git a/src/LexCSS.cxx b/src/LexCSS.cxx
new file mode 100644
index 000000000..fcf39a5c1
--- /dev/null
+++ b/src/LexCSS.cxx
@@ -0,0 +1,234 @@
+// Scintilla source code edit control
+/** @file LexCSS.cxx
+ ** Lexer for Cascade Style Sheets
+ ** Written by Jakub Vrána
+ **/
+// Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
+// The License.txt file describes the conditions under which this software may be distributed.
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "Platform.h"
+
+#include "PropSet.h"
+#include "Accessor.h"
+#include "StyleContext.h"
+#include "KeyWords.h"
+#include "Scintilla.h"
+#include "SciLexer.h"
+
+
+
+static inline bool IsAWordChar(const unsigned int ch) {
+ return (isalnum(ch) || ch == '-' || ch >= 161);
+}
+
+inline bool IsCssOperator(const char ch) {
+ if (!isalnum(ch) && (ch == '{' || ch == '}' || ch == ':' || ch == ',' || ch == ';' || ch == '.' || ch == '#' || ch == '!' || ch == '@'))
+ return true;
+ return false;
+}
+
+static void ColouriseCssDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) {
+ WordList &keywords = *keywordlists[0];
+ WordList &pseudoClasses = *keywordlists[1];
+
+ StyleContext sc(startPos, length, initStyle, styler);
+
+ int lastState = -1; // before operator
+ int lastStateC = -1; // before comment
+ int op = ' '; // last operator
+
+ for (; sc.More(); sc.Forward()) {
+ if (sc.state == SCE_CSS_COMMENT && sc.Match('*', '/')) {
+ if (lastStateC == -1) {
+ // backtrack to get last state
+ unsigned int i = startPos;
+ for (; i > 0; i--) {
+ if ((lastStateC = styler.StyleAt(i-1)) != SCE_CSS_COMMENT) {
+ if (lastStateC == SCE_CSS_OPERATOR) {
+ op = styler.SafeGetCharAt(i-1);
+ while (--i) {
+ lastState = styler.StyleAt(i-1);
+ if (lastState != SCE_CSS_OPERATOR && lastState != SCE_CSS_COMMENT)
+ break;
+ }
+ if (i == 0)
+ lastState = SCE_CSS_DEFAULT;
+ }
+ break;
+ }
+ }
+ if (i == 0)
+ lastStateC = SCE_CSS_DEFAULT;
+ }
+ sc.Forward();
+ sc.ForwardSetState(lastStateC);
+ }
+
+ if (sc.state == SCE_CSS_COMMENT)
+ continue;
+
+ if (sc.state == SCE_CSS_OPERATOR) {
+ if (op == ' ') {
+ unsigned int i = startPos;
+ op = styler.SafeGetCharAt(i-1);
+ while (--i) {
+ lastState = styler.StyleAt(i-1);
+ if (lastState != SCE_CSS_OPERATOR && lastState != SCE_CSS_COMMENT)
+ break;
+ }
+ }
+ switch (op) {
+ case '@':
+ if (lastState == SCE_CSS_DEFAULT)
+ sc.SetState(SCE_CSS_DIRECTIVE);
+ break;
+ case '{':
+ if (lastState == SCE_CSS_DIRECTIVE)
+ sc.SetState(SCE_CSS_DEFAULT);
+ else if (lastState == SCE_CSS_TAG)
+ sc.SetState(SCE_CSS_IDENTIFIER);
+ break;
+ case '}':
+ if (lastState == SCE_CSS_DEFAULT || lastState == SCE_CSS_VALUE || lastState == SCE_CSS_IMPORTANT || lastState == SCE_CSS_IDENTIFIER)
+ sc.SetState(SCE_CSS_DEFAULT);
+ break;
+ case ':':
+ if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_DEFAULT || lastState == SCE_CSS_CLASS || lastState == SCE_CSS_ID)
+ sc.SetState(SCE_CSS_PSEUDOCLASS);
+ else if (lastState == SCE_CSS_IDENTIFIER || SCE_CSS_UNKNOWN_IDENTIFIER)
+ sc.SetState(SCE_CSS_VALUE);
+ break;
+ case '.':
+ if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_DEFAULT)
+ sc.SetState(SCE_CSS_CLASS);
+ break;
+ case '#':
+ if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_DEFAULT)
+ sc.SetState(SCE_CSS_ID);
+ break;
+ case ',':
+ if (lastState == SCE_CSS_TAG)
+ sc.SetState(SCE_CSS_DEFAULT);
+ break;
+ case ';':
+ if (lastState == SCE_CSS_DIRECTIVE)
+ sc.SetState(SCE_CSS_DEFAULT);
+ else if (lastState == SCE_CSS_VALUE || lastState == SCE_CSS_IMPORTANT)
+ sc.SetState(SCE_CSS_IDENTIFIER);
+ break;
+ case '!':
+ if (lastState == SCE_CSS_VALUE)
+ sc.SetState(SCE_CSS_IMPORTANT);
+ break;
+ }
+ }
+
+ if (IsAWordChar(sc.ch)) {
+ if (sc.state == SCE_CSS_DEFAULT)
+ sc.SetState(SCE_CSS_TAG);
+ continue;
+ }
+
+ if (IsAWordChar(sc.chPrev) && (sc.state == SCE_CSS_IDENTIFIER || sc.state == SCE_CSS_PSEUDOCLASS || sc.state == SCE_CSS_IMPORTANT)) {
+ char s[100];
+ sc.GetCurrentLowered(s, sizeof(s));
+ char *s2 = s;
+ while (*s2 && !IsAWordChar(*s2))
+ s2++;
+ switch (sc.state) {
+ case SCE_CSS_IDENTIFIER:
+ if (!keywords.InList(s2))
+ sc.ChangeState(SCE_CSS_UNKNOWN_IDENTIFIER);
+ break;
+ case SCE_CSS_PSEUDOCLASS:
+ if (!pseudoClasses.InList(s2))
+ sc.ChangeState(SCE_CSS_UNKNOWN_PSEUDOCLASS);
+ break;
+ case SCE_CSS_IMPORTANT:
+ if (strcmp(s2, "important") != 0)
+ sc.ChangeState(SCE_CSS_VALUE);
+ break;
+ }
+ }
+
+ if (sc.ch != '.' && sc.ch != ':' && sc.ch != '#' && (sc.state == SCE_CSS_CLASS || sc.state == SCE_CSS_PSEUDOCLASS || sc.state == SCE_CSS_UNKNOWN_PSEUDOCLASS || sc.state == SCE_CSS_UNKNOWN_PSEUDOCLASS || sc.state == SCE_CSS_ID))
+ sc.SetState(SCE_CSS_TAG);
+
+ if (sc.Match('/', '*')) {
+ lastStateC = sc.state;
+ sc.SetState(SCE_CSS_COMMENT);
+ sc.Forward();
+ continue;
+ }
+
+ if (IsCssOperator(sc.ch)
+ && (sc.state != SCE_CSS_VALUE || sc.ch == ';' || sc.ch == '}' || sc.ch == '!')
+ && (sc.state != SCE_CSS_DIRECTIVE || sc.ch == ';' || sc.ch == '{')
+ ) {
+ if (sc.state != SCE_CSS_OPERATOR)
+ lastState = sc.state;
+ sc.SetState(SCE_CSS_OPERATOR);
+ op = sc.ch;
+ }
+ }
+
+ sc.Complete();
+}
+
+static void FoldCSSDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {
+ bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
+ bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
+ unsigned int endPos = startPos + length;
+ int visibleChars = 0;
+ int lineCurrent = styler.GetLine(startPos);
+ int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
+ int levelCurrent = levelPrev;
+ char chNext = styler[startPos];
+ bool inComment = (styler.StyleAt(startPos-1) == SCE_CSS_COMMENT);
+ for (unsigned int i = startPos; i < endPos; i++) {
+ char ch = chNext;
+ chNext = styler.SafeGetCharAt(i + 1);
+ int style = styler.StyleAt(i);
+ bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
+ if (foldComment) {
+ if (!inComment && (style == SCE_CSS_COMMENT))
+ levelCurrent++;
+ else if (inComment && (style != SCE_CSS_COMMENT))
+ levelCurrent--;
+ inComment = (style == SCE_CSS_COMMENT);
+ }
+ if (style == SCE_CSS_OPERATOR) {
+ if (ch == '{') {
+ levelCurrent++;
+ } else if (ch == '}') {
+ levelCurrent--;
+ }
+ }
+ if (atEOL) {
+ int lev = levelPrev;
+ if (visibleChars == 0 && foldCompact)
+ lev |= SC_FOLDLEVELWHITEFLAG;
+ if ((levelCurrent > levelPrev) && (visibleChars > 0))
+ lev |= SC_FOLDLEVELHEADERFLAG;
+ if (lev != styler.LevelAt(lineCurrent)) {
+ styler.SetLevel(lineCurrent, lev);
+ }
+ lineCurrent++;
+ levelPrev = levelCurrent;
+ visibleChars = 0;
+ }
+ if (!isspacechar(ch))
+ visibleChars++;
+ }
+ // Fill in the real level of the next line, keeping the current flags as they will be filled in later
+ int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
+ styler.SetLevel(lineCurrent, levelPrev | flagsNext);
+}
+
+LexerModule lmCss(SCLEX_CSS, ColouriseCssDoc, "css", FoldCSSDoc);
diff --git a/src/LexHTML.cxx b/src/LexHTML.cxx
index 545bbfd55..687e2c533 100644
--- a/src/LexHTML.cxx
+++ b/src/LexHTML.cxx
@@ -368,6 +368,14 @@ static inline bool issgmlwordchar(char ch) {
return isalnum(ch) || ch == '.' || ch == '_' || ch == ':' || ch == '!' || ch == '#' || ch == '[';
}
+static inline bool IsPhpWordStart(const unsigned char ch) {
+ return isalpha(ch) || (ch == '_') || (ch >= 0x7f);
+}
+
+static inline bool IsPhpWordChar(char ch) {
+ return isdigit(ch) || IsPhpWordStart(ch);
+}
+
static bool InTagState(int state) {
return state == SCE_H_TAG || state == SCE_H_TAGUNKNOWN ||
state == SCE_H_SCRIPT ||
@@ -481,7 +489,9 @@ static void ColouriseHyperTextDoc(unsigned int startPos, int length, int initSty
case eScriptPHP:
//not currently supported case eScriptVBS:
- if ((state != SCE_HPHP_COMMENT) && (state != SCE_HPHP_COMMENTLINE) && (state != SCE_HJ_COMMENT) && (state != SCE_HJ_COMMENTLINE) && (state != SCE_HJ_COMMENTDOC)) {
+ /* if ((state != SCE_HPHP_COMMENT) && (state != SCE_HPHP_COMMENTLINE) && (state != SCE_HJ_COMMENT) && (state != SCE_HJ_COMMENTLINE) && (state != SCE_HJ_COMMENTDOC)) { */
+ //Platform::DebugPrintf("state=%d, StateToPrint=%d, initStyle=%d\n", state, StateToPrint, initStyle);
+ if ((state == SCE_HPHP_OPERATOR) || (state == SCE_HPHP_DEFAULT) || (state == SCE_HJ_SYMBOLS) || (state == SCE_HJ_START) || (state == SCE_HJ_DEFAULT)) {
if ((ch == '{') || (ch == '}')) {
levelCurrent += (ch == '{') ? 1 : -1;
}
@@ -1044,10 +1054,10 @@ static void ColouriseHyperTextDoc(unsigned int startPos, int length, int initSty
break;
case SCE_H_VALUE:
if (!ishtmlwordchar(ch)) {
- if (ch == '\"') {
+ if (ch == '\"' && chPrev == '=') {
// Should really test for being first character
state = SCE_H_DOUBLESTRING;
- } else if (ch == '\'') {
+ } else if (ch == '\'' && chPrev == '=') {
state = SCE_H_SINGLESTRING;
} else {
if (IsNumber(styler.GetStartSegment(), styler)) {
@@ -1397,7 +1407,7 @@ static void ColouriseHyperTextDoc(unsigned int startPos, int length, int initSty
break;
///////////// start - PHP state handling
case SCE_HPHP_WORD:
- if (!iswordstart(ch)) {
+ if (!iswordchar(ch)) {
classifyWordHTPHP(styler.GetStartSegment(), i - 1, keywords5, styler);
if (ch == '/' && chNext == '*') {
i++;
@@ -1411,7 +1421,7 @@ static void ColouriseHyperTextDoc(unsigned int startPos, int length, int initSty
state = SCE_HPHP_HSTRING;
} else if (ch == '\'') {
state = SCE_HPHP_SIMPLESTRING;
- } else if (ch == '$') {
+ } else if (ch == '$' && IsPhpWordStart(chNext)) {
state = SCE_HPHP_VARIABLE;
} else if (isoperator(ch)) {
state = SCE_HPHP_OPERATOR;
@@ -1430,7 +1440,7 @@ static void ColouriseHyperTextDoc(unsigned int startPos, int length, int initSty
}
break;
case SCE_HPHP_VARIABLE:
- if (!iswordstart(ch)) {
+ if (!IsPhpWordChar(ch)) {
styler.ColourTo(i - 1, SCE_HPHP_VARIABLE);
if (isoperator(ch))
state = SCE_HPHP_OPERATOR;
@@ -1454,7 +1464,7 @@ static void ColouriseHyperTextDoc(unsigned int startPos, int length, int initSty
if (ch == '\\') {
// skip the next char
i++;
- } else if (ch == '$') {
+ } else if (ch == '$' && IsPhpWordStart(chNext)) {
styler.ColourTo(i - 1, StateToPrint);
state = SCE_HPHP_HSTRING_VARIABLE;
} else if (ch == '\"') {
@@ -1472,7 +1482,7 @@ static void ColouriseHyperTextDoc(unsigned int startPos, int length, int initSty
}
break;
case SCE_HPHP_HSTRING_VARIABLE:
- if (!iswordstart(ch)) {
+ if (!IsPhpWordChar(ch)) {
styler.ColourTo(i - 1, StateToPrint);
i--; // strange but it works
state = SCE_HPHP_HSTRING;
@@ -1497,7 +1507,7 @@ static void ColouriseHyperTextDoc(unsigned int startPos, int length, int initSty
state = SCE_HPHP_HSTRING;
} else if (ch == '\'') {
state = SCE_HPHP_SIMPLESTRING;
- } else if (ch == '$') {
+ } else if (ch == '$' && IsPhpWordStart(chNext)) {
state = SCE_HPHP_VARIABLE;
} else if (isoperator(ch)) {
state = SCE_HPHP_OPERATOR;
@@ -1553,7 +1563,7 @@ static void ColouriseHyperTextDoc(unsigned int startPos, int length, int initSty
}
StateToPrint = statePrintForState(state, inScriptType);
- styler.ColourTo(lengthDoc - 1, StateToPrint);
+ styler.ColourTo(lengthDoc - 1, StateToPrint);
// Fill in the real level of the next line, keeping the current flags as they will be filled in later
if (fold) {
@@ -1701,9 +1711,9 @@ static void ColouriseHTMLPiece(StyleContext &sc, WordList *keywordlists[]) {
sc.SetState(SCE_H_ENTITY);
}
} else if ((sc.state == SCE_H_OTHER) || (sc.state == SCE_H_VALUE)) {
- if (sc.ch == '\"') {
+ if (sc.ch == '\"' && sc.chPrev == '=') {
sc.SetState(SCE_H_DOUBLESTRING);
- } else if (sc.ch == '\'') {
+ } else if (sc.ch == '\'' && sc.chPrev == '=') {
sc.SetState(SCE_H_SINGLESTRING);
} else if (IsADigit(sc.ch)) {
sc.SetState(SCE_H_NUMBER);
@@ -1780,7 +1790,7 @@ static void ColourisePHPPiece(StyleContext &sc, WordList *keywordlists[]) {
// Handle some PHP script
if (sc.state == SCE_HPHP_WORD) {
- if (!IsAWordStart(sc.ch)) {
+ if (!IsPhpWordChar(sc.ch)) {
sc.SetState(SCE_HPHP_DEFAULT);
}
} else if (sc.state == SCE_HPHP_COMMENTLINE) {
@@ -1802,7 +1812,7 @@ static void ColourisePHPPiece(StyleContext &sc, WordList *keywordlists[]) {
sc.ForwardSetState(SCE_HPHP_DEFAULT);
}
} else if (sc.state == SCE_HPHP_VARIABLE) {
- if (!IsAWordStart(sc.ch)) {
+ if (!IsPhpWordChar(sc.ch)) {
sc.SetState(SCE_HPHP_DEFAULT);
}
} else if (sc.state == SCE_HPHP_OPERATOR) {
@@ -1822,7 +1832,7 @@ static void ColourisePHPPiece(StyleContext &sc, WordList *keywordlists[]) {
}
}
if (sc.state == SCE_HPHP_DEFAULT) {
- if (IsAWordStart(sc.ch)) {
+ if (IsPhpWordStart(sc.ch)) {
sc.SetState(SCE_HPHP_WORD);
} else if (sc.ch == '#') {
sc.SetState(SCE_HPHP_COMMENTLINE);
@@ -1836,7 +1846,7 @@ static void ColourisePHPPiece(StyleContext &sc, WordList *keywordlists[]) {
sc.SetState(SCE_HPHP_HSTRING);
} else if (sc.ch == '\'') {
sc.SetState(SCE_HPHP_SIMPLESTRING);
- } else if (sc.ch == '$') {
+ } else if (sc.ch == '$' && IsPhpWordStart(sc.chNext)) {
sc.SetState(SCE_HPHP_VARIABLE);
} else if (isoperator(static_cast<char>(sc.ch))) {
sc.SetState(SCE_HPHP_OPERATOR);