diff --git a/doc/LexillaHistory.html b/doc/LexillaHistory.html
index c0076ee9..81bc6dd3 100644
--- a/doc/LexillaHistory.html
+++ b/doc/LexillaHistory.html
@@ -611,6 +611,10 @@
+ PHP: Fix unstable lexing with substyled keyword and unterminated string.
+ Issue #288.
+
+
TOML: Don't treat keys without values as errors.
Pull request #283.
diff --git a/lexers/LexHTML.cxx b/lexers/LexHTML.cxx
index 51cac259..b384368d 100644
--- a/lexers/LexHTML.cxx
+++ b/lexers/LexHTML.cxx
@@ -668,6 +668,10 @@ constexpr bool isPHPStringState(int state) noexcept {
(state == SCE_HPHP_COMPLEX_VARIABLE);
}
+constexpr bool StyleNeedsBacktrack(int state) noexcept {
+ return InTagState(state) || isPHPStringState(state);
+}
+
enum class AllowPHP : int {
None, // No PHP
PHP, // 0) && (InTagState(styler.StyleIndexAt(startPos - 1)))) {
+ // PHP string can be heredoc, must find a delimiter first. Reread from beginning of line containing the string, to get the correct lineState
+ if (StyleNeedsBacktrack(state)) {
+ while ((startPos > 0) && (StyleNeedsBacktrack(styler.StyleIndexAt(startPos - 1)))) {
const Sci_Position backLineStart = styler.LineStart(styler.GetLine(startPos-1));
length += startPos - backLineStart;
startPos = backLineStart;
}
- state = (startPos > 0) ? styler.StyleIndexAt(startPos - 1) : SCE_H_DEFAULT;
- }
- // String can be heredoc, must find a delimiter first. Reread from beginning of line containing the string, to get the correct lineState
- if (isPHPStringState(state)) {
- while (startPos > 0 && (isPHPStringState(state) || !isLineEnd(styler[startPos - 1]))) {
- startPos--;
- length++;
- state = styler.StyleIndexAt(startPos);
+ if (startPos > 0) {
+ state = styler.StyleIndexAt(startPos - 1);
+ } else {
+ state = isPHPScript ? SCE_HPHP_DEFAULT : SCE_H_DEFAULT;
}
- if (startPos == 0)
- state = SCE_H_DEFAULT;
}
styler.StartAt(startPos);
diff --git a/test/examples/hypertext/Issue288.php b/test/examples/hypertext/Issue288.php
new file mode 100644
index 00000000..f368517e
--- /dev/null
+++ b/test/examples/hypertext/Issue288.php
@@ -0,0 +1,4 @@
+
+nl2br("\n); // unterminated string
+?>
+")
diff --git a/test/examples/hypertext/Issue288.php.folded b/test/examples/hypertext/Issue288.php.folded
new file mode 100644
index 00000000..829aab7f
--- /dev/null
+++ b/test/examples/hypertext/Issue288.php.folded
@@ -0,0 +1,5 @@
+ 2 400 0 +
+ 0 401 0 | nl2br("\n); // unterminated string
+ 0 401 0 | ?>
+ 0 401 0 | ")
+ 0 401 0 |
\ No newline at end of file
diff --git a/test/examples/hypertext/Issue288.php.styled b/test/examples/hypertext/Issue288.php.styled
new file mode 100644
index 00000000..125b26ef
--- /dev/null
+++ b/test/examples/hypertext/Issue288.php.styled
@@ -0,0 +1,4 @@
+{18}{118}
+{198}nl2br{127}({119}"\n); // unterminated string
+?>
+"{127}){118}
diff --git a/test/examples/hypertext/SciTE.properties b/test/examples/hypertext/SciTE.properties
index b3810c4e..8d7846b1 100644
--- a/test/examples/hypertext/SciTE.properties
+++ b/test/examples/hypertext/SciTE.properties
@@ -33,7 +33,7 @@ substyles.hypertext.96=1
substylewords.96.1.*=parse
# PHP
substyles.hypertext.121=1
-substylewords.121.1.*=decrypt
+substylewords.121.1.*=decrypt nl2br
fold=1
fold.html=1