From 7a06bad41ba39a5028a824315231412d82ec2bd1 Mon Sep 17 00:00:00 2001 From: Josh Goebel Date: Thu, 9 Dec 2021 18:29:13 -0500 Subject: [PATCH 1/9] chore(php) rewrite keyword lists to arrays --- src/languages/php.js | 204 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 189 insertions(+), 15 deletions(-) diff --git a/src/languages/php.js b/src/languages/php.js index ce0af400a8..b051c266b5 100644 --- a/src/languages/php.js +++ b/src/languages/php.js @@ -71,36 +71,210 @@ export default function(hljs) { ], relevance: 0 }; - const KEYWORDS = { - keyword: + const LITERALS = [ + "false", + "null", + "true" + ]; + const KWS = [ // Magic constants: // - '__CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__ __TRAIT__ ' + + "__CLASS__", + "__DIR__", + "__FILE__", + "__FUNCTION__", + "__LINE__", + "__METHOD__", + "__NAMESPACE__", + "__TRAIT__", // Function that look like language construct or language construct that look like function: // List of keywords that may not require parenthesis - 'die echo exit include include_once print require require_once ' + + "die", + "echo", + "exit", + "include", + "include_once", + "print", + "require", + "require_once", // These are not language construct (function) but operate on the currently-executing function and can access the current symbol table // 'compact extract func_get_arg func_get_args func_num_args get_called_class get_parent_class ' + // Other keywords: // // - 'array abstract and as binary bool boolean break callable case catch class clone const continue declare ' + - 'default do double else elseif empty enddeclare endfor endforeach endif endswitch endwhile enum eval extends ' + - 'final finally float for foreach from global goto if implements instanceof insteadof int integer interface ' + - 'isset iterable list match|0 mixed new object or private protected public real return string switch throw trait ' + - 'try unset use var void while xor yield', - literal: 'false null true', - built_in: + "array", + "abstract", + "and", + "as", + "binary", + "bool", + "boolean", + "break", + "callable", + "case", + "catch", + "class", + "clone", + "const", + "continue", + "declare", + "default", + "do", + "double", + "else", + "elseif", + "empty", + "enddeclare", + "endfor", + "endforeach", + "endif", + "endswitch", + "endwhile", + "enum", + "eval", + "extends", + "final", + "finally", + "float", + "for", + "foreach", + "from", + "global", + "goto", + "if", + "implements", + "instanceof", + "insteadof", + "int", + "integer", + "interface", + "isset", + "iterable", + "list", + "match|0", + "mixed", + "new", + "object", + "or", + "private", + "protected", + "public", + "real", + "return", + "string", + "switch", + "throw", + "trait", + "try", + "unset", + "use", + "var", + "void", + "while", + "xor", + "yield" + ]; + + const BUILT_INS = [ // Standard PHP library: // - 'Error|0 ' + // error is too common a name esp since PHP is case in-sensitive - 'AppendIterator ArgumentCountError ArithmeticError ArrayIterator ArrayObject AssertionError BadFunctionCallException BadMethodCallException CachingIterator CallbackFilterIterator CompileError Countable DirectoryIterator DivisionByZeroError DomainException EmptyIterator ErrorException Exception FilesystemIterator FilterIterator GlobIterator InfiniteIterator InvalidArgumentException IteratorIterator LengthException LimitIterator LogicException MultipleIterator NoRewindIterator OutOfBoundsException OutOfRangeException OuterIterator OverflowException ParentIterator ParseError RangeException RecursiveArrayIterator RecursiveCachingIterator RecursiveCallbackFilterIterator RecursiveDirectoryIterator RecursiveFilterIterator RecursiveIterator RecursiveIteratorIterator RecursiveRegexIterator RecursiveTreeIterator RegexIterator RuntimeException SeekableIterator SplDoublyLinkedList SplFileInfo SplFileObject SplFixedArray SplHeap SplMaxHeap SplMinHeap SplObjectStorage SplObserver SplObserver SplPriorityQueue SplQueue SplStack SplSubject SplSubject SplTempFileObject TypeError UnderflowException UnexpectedValueException UnhandledMatchError ' + + "Error|0", + "AppendIterator", + "ArgumentCountError", + "ArithmeticError", + "ArrayIterator", + "ArrayObject", + "AssertionError", + "BadFunctionCallException", + "BadMethodCallException", + "CachingIterator", + "CallbackFilterIterator", + "CompileError", + "Countable", + "DirectoryIterator", + "DivisionByZeroError", + "DomainException", + "EmptyIterator", + "ErrorException", + "Exception", + "FilesystemIterator", + "FilterIterator", + "GlobIterator", + "InfiniteIterator", + "InvalidArgumentException", + "IteratorIterator", + "LengthException", + "LimitIterator", + "LogicException", + "MultipleIterator", + "NoRewindIterator", + "OutOfBoundsException", + "OutOfRangeException", + "OuterIterator", + "OverflowException", + "ParentIterator", + "ParseError", + "RangeException", + "RecursiveArrayIterator", + "RecursiveCachingIterator", + "RecursiveCallbackFilterIterator", + "RecursiveDirectoryIterator", + "RecursiveFilterIterator", + "RecursiveIterator", + "RecursiveIteratorIterator", + "RecursiveRegexIterator", + "RecursiveTreeIterator", + "RegexIterator", + "RuntimeException", + "SeekableIterator", + "SplDoublyLinkedList", + "SplFileInfo", + "SplFileObject", + "SplFixedArray", + "SplHeap", + "SplMaxHeap", + "SplMinHeap", + "SplObjectStorage", + "SplObserver", + "SplObserver", + "SplPriorityQueue", + "SplQueue", + "SplStack", + "SplSubject", + "SplSubject", + "SplTempFileObject", + "TypeError", + "UnderflowException", + "UnexpectedValueException", + "UnhandledMatchError", // Reserved interfaces: // - 'ArrayAccess Closure Generator Iterator IteratorAggregate Serializable Stringable Throwable Traversable WeakReference WeakMap ' + + "ArrayAccess", + "Closure", + "Generator", + "Iterator", + "IteratorAggregate", + "Serializable", + "Stringable", + "Throwable", + "Traversable", + "WeakReference", + "WeakMap", // Reserved classes: // - 'Directory __PHP_Incomplete_Class parent php_user_filter self static stdClass' + "Directory", + "__PHP_Incomplete_Class", + "parent", + "php_user_filter", + "self", + "static", + "stdClass" + ]; + + const KEYWORDS = { + keyword: KWS, + literal: LITERALS, + built_in: BUILT_INS }; return { case_insensitive: true, From c4a068b7fc923230e72d745257ce34e9c72dca7a Mon Sep 17 00:00:00 2001 From: Josh Goebel Date: Thu, 9 Dec 2021 18:38:58 -0500 Subject: [PATCH 2/9] enh(php) improve namespace/use highlighting --- src/languages/php.js | 17 +++++++++++++++-- test/markup/php/namespace.expect.txt | 8 ++++++++ test/markup/php/namespace.txt | 8 ++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 test/markup/php/namespace.expect.txt create mode 100644 test/markup/php/namespace.txt diff --git a/src/languages/php.js b/src/languages/php.js index b051c266b5..2e9c8c318d 100644 --- a/src/languages/php.js +++ b/src/languages/php.js @@ -355,18 +355,31 @@ export default function(hljs) { hljs.UNDERSCORE_TITLE_MODE ] }, + // both use and namespace still use "old style" rules (vs multi-match) + // because the namespace name can include `\` and we still want each + // element to be treated as it's own *individual* title { beginKeywords: 'namespace', relevance: 0, end: ';', illegal: /[.']/, - contains: [hljs.UNDERSCORE_TITLE_MODE] + contains: [ + hljs.inherit(hljs.UNDERSCORE_TITLE_MODE, { scope: "title.class" }) + ] }, { beginKeywords: 'use', relevance: 0, end: ';', - contains: [hljs.UNDERSCORE_TITLE_MODE] + contains: [ + // TODO: title.function vs title.class + { + match: /\b(as|const|function)\b/, + scope: "keyword" + }, + // TODO: could be title.class or title.function + hljs.UNDERSCORE_TITLE_MODE + ] }, STRING, NUMBER diff --git a/test/markup/php/namespace.expect.txt b/test/markup/php/namespace.expect.txt new file mode 100644 index 0000000000..8b907e1873 --- /dev/null +++ b/test/markup/php/namespace.expect.txt @@ -0,0 +1,8 @@ +namespace Location\Web; +namespace foo; +use My\Full\Classname as Another; +use My\Full\NSname; +use ArrayObject; +use function My\Full\functionName; +use function My\Full\functionName as func; +use const My\Full\CONSTANT; diff --git a/test/markup/php/namespace.txt b/test/markup/php/namespace.txt new file mode 100644 index 0000000000..cbb313094b --- /dev/null +++ b/test/markup/php/namespace.txt @@ -0,0 +1,8 @@ +namespace Location\Web; +namespace foo; +use My\Full\Classname as Another; +use My\Full\NSname; +use ArrayObject; +use function My\Full\functionName; +use function My\Full\functionName as func; +use const My\Full\CONSTANT; From e158fbd599a4dce053dc6a0ca9d69d401b6979ce Mon Sep 17 00:00:00 2001 From: Josh Goebel Date: Thu, 9 Dec 2021 18:57:05 -0500 Subject: [PATCH 3/9] chore(php) comments should not care about pre-processor - this should be handled by php-template level (not php) --- src/languages/php.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languages/php.js b/src/languages/php.js index 2e9c8c318d..96e2aec158 100644 --- a/src/languages/php.js +++ b/src/languages/php.js @@ -281,7 +281,7 @@ export default function(hljs) { keywords: KEYWORDS, contains: [ hljs.HASH_COMMENT_MODE, - hljs.COMMENT('//', '$', {contains: [PREPROCESSOR]}), + hljs.COMMENT('//', '$'), hljs.COMMENT( '/\\*', '\\*/', From f5616e16ce6d3a2ef15a353bd23b3e0a6d4c140f Mon Sep 17 00:00:00 2001 From: Josh Goebel Date: Thu, 9 Dec 2021 19:09:08 -0500 Subject: [PATCH 4/9] chore(php) remove dead contains rule This rule wasn't even being used since each of the variants already has it's own contains, so this one would never have a change to be "default". --- src/languages/php.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/languages/php.js b/src/languages/php.js index 96e2aec158..1fd109a844 100644 --- a/src/languages/php.js +++ b/src/languages/php.js @@ -47,13 +47,14 @@ export default function(hljs) { }); const STRING = { className: 'string', - contains: [hljs.BACKSLASH_ESCAPE, PREPROCESSOR], variants: [ hljs.inherit(SINGLE_QUOTED, { - begin: "b'", end: "'", + begin: "b'", + end: "'", }), hljs.inherit(DOUBLE_QUOTED, { - begin: 'b"', end: '"', + begin: 'b"', + end: '"', }), DOUBLE_QUOTED, SINGLE_QUOTED, From 6e116aa6ffed4d1dedc50b5004e771049be81803 Mon Sep 17 00:00:00 2001 From: Josh Goebel Date: Thu, 9 Dec 2021 19:12:45 -0500 Subject: [PATCH 5/9] enh(php) $this is a variable.language --- src/languages/php.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/languages/php.js b/src/languages/php.js index 1fd109a844..4b04e71acb 100644 --- a/src/languages/php.js +++ b/src/languages/php.js @@ -305,7 +305,8 @@ export default function(hljs) { ), PREPROCESSOR, { - className: 'keyword', begin: /\$this\b/ + className: 'variable.language', + begin: /\$this\b/ }, VARIABLE, { From 38ebe60d766dd9f093fc736069c7e76843f34a29 Mon Sep 17 00:00:00 2001 From: Josh Goebel Date: Thu, 9 Dec 2021 19:34:09 -0500 Subject: [PATCH 6/9] chore(php) no binary strings, was a 6.0 only thing --- src/languages/php.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/languages/php.js b/src/languages/php.js index 4b04e71acb..97f8e8d048 100644 --- a/src/languages/php.js +++ b/src/languages/php.js @@ -48,14 +48,6 @@ export default function(hljs) { const STRING = { className: 'string', variants: [ - hljs.inherit(SINGLE_QUOTED, { - begin: "b'", - end: "'", - }), - hljs.inherit(DOUBLE_QUOTED, { - begin: 'b"', - end: '"', - }), DOUBLE_QUOTED, SINGLE_QUOTED, HEREDOC From 5907a6025aeabf3f47d37ee2a5828cb4d63922ca Mon Sep 17 00:00:00 2001 From: Josh Goebel Date: Thu, 9 Dec 2021 19:48:48 -0500 Subject: [PATCH 7/9] enh(php) add __COMPILER_HALT_OFFSET__ --- src/languages/php.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/languages/php.js b/src/languages/php.js index 97f8e8d048..e835d2feec 100644 --- a/src/languages/php.js +++ b/src/languages/php.js @@ -76,6 +76,7 @@ export default function(hljs) { "__DIR__", "__FILE__", "__FUNCTION__", + "__COMPILER_HALT_OFFSET__", "__LINE__", "__METHOD__", "__NAMESPACE__", @@ -289,7 +290,7 @@ export default function(hljs) { ), hljs.COMMENT( '__halt_compiler.+?;', - false, + null, { endsWithParent: true, keywords: '__halt_compiler' From fc6bcc95840d4839881af566ca7234767459ad71 Mon Sep 17 00:00:00 2001 From: Josh Goebel Date: Thu, 9 Dec 2021 20:23:43 -0500 Subject: [PATCH 8/9] chore(php) more correct __halt_compiler(); --- src/languages/php.js | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/languages/php.js b/src/languages/php.js index e835d2feec..66d1a94f73 100644 --- a/src/languages/php.js +++ b/src/languages/php.js @@ -288,14 +288,21 @@ export default function(hljs) { ] } ), - hljs.COMMENT( - '__halt_compiler.+?;', - null, - { - endsWithParent: true, - keywords: '__halt_compiler' + { + match: /__halt_compiler\(\);/, + keywords: '__halt_compiler', + starts: { + scope: "comment", + end: hljs.MATCH_NOTHING_RE, + contains: [ + { + match: /\?>/, + scope: "meta", + endsParent: true + } + ] } - ), + }, PREPROCESSOR, { className: 'variable.language', From c5e405f8c8cf0b92fd96b55304a10e64464d4901 Mon Sep 17 00:00:00 2001 From: Josh Goebel Date: Fri, 10 Dec 2021 12:39:47 -0500 Subject: [PATCH 9/9] chore(php) add changelog for PHP improvements --- CHANGES.md | 3 +++ src/languages/php.js | 2 -- test/markup/php/namespace.expect.txt | 1 + test/markup/php/namespace.txt | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index b2294ae731..6bafdafe09 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,9 @@ These changes should be for the better and should not be super noticeable but if Grammars: +- enh(php) improve `namespace` and `use` highlighting (#3427) [Josh Goebel][] +- enh(php) `$this` is a `variable.language` now (#3427) [Josh Goebel][] +- enh(php) add `__COMPILER_HALT_OFFSET__` (#3427) [Josh Goebel][] - enh(js/ts) fix => async function title highlights (#3405) [Josh Goebel][] - enh(twig) update keywords list (#3415) [Matthieu Lempereur][] - fix(python) def, class keywords detected mid-identifier (#3381) [Josh Goebel][] diff --git a/src/languages/php.js b/src/languages/php.js index 66d1a94f73..b0736a2014 100644 --- a/src/languages/php.js +++ b/src/languages/php.js @@ -230,12 +230,10 @@ export default function(hljs) { "SplMinHeap", "SplObjectStorage", "SplObserver", - "SplObserver", "SplPriorityQueue", "SplQueue", "SplStack", "SplSubject", - "SplSubject", "SplTempFileObject", "TypeError", "UnderflowException", diff --git a/test/markup/php/namespace.expect.txt b/test/markup/php/namespace.expect.txt index 8b907e1873..338c6d38a8 100644 --- a/test/markup/php/namespace.expect.txt +++ b/test/markup/php/namespace.expect.txt @@ -6,3 +6,4 @@ use function My\Full\functionName; use function My\Full\functionName as func; use const My\Full\CONSTANT; +use Example\{ClassA, ClassB, ClassC as C}; diff --git a/test/markup/php/namespace.txt b/test/markup/php/namespace.txt index cbb313094b..c2f16b7f01 100644 --- a/test/markup/php/namespace.txt +++ b/test/markup/php/namespace.txt @@ -6,3 +6,4 @@ use ArrayObject; use function My\Full\functionName; use function My\Full\functionName as func; use const My\Full\CONSTANT; +use Example\{ClassA, ClassB, ClassC as C};