diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -237,6 +237,7 @@ 'PhutilProtocolChannel' => 'channel/PhutilProtocolChannel.php', 'PhutilProxyException' => 'error/PhutilProxyException.php', 'PhutilPygmentsSyntaxHighlighter' => 'markup/syntax/highlighter/PhutilPygmentsSyntaxHighlighter.php', + 'PhutilPythonFragmentLexer' => 'lexer/PhutilPythonFragmentLexer.php', 'PhutilQsprintfInterface' => 'xsprintf/PhutilQsprintfInterface.php', 'PhutilQueryStringParser' => 'parser/PhutilQueryStringParser.php', 'PhutilQueryStringParserTestCase' => 'parser/__tests__/PhutilQueryStringParserTestCase.php', @@ -619,6 +620,7 @@ 'PhutilProcessGroupDaemon' => 'PhutilTortureTestDaemon', 'PhutilProtocolChannel' => 'PhutilChannelChannel', 'PhutilProxyException' => 'Exception', + 'PhutilPythonFragmentLexer' => 'PhutilLexer', 'PhutilQueryStringParserTestCase' => 'PhutilTestCase', 'PhutilReadableSerializerTestCase' => 'PhutilTestCase', 'PhutilRealnameContextFreeGrammar' => 'PhutilContextFreeGrammar', diff --git a/src/lexer/PhutilPythonFragmentLexer.php b/src/lexer/PhutilPythonFragmentLexer.php new file mode 100644 --- /dev/null +++ b/src/lexer/PhutilPythonFragmentLexer.php @@ -0,0 +1,315 @@ + array_merge(array( + array('\\n', null), + // TODO: Docstrings should match only at the start of a line + array('""".*?"""', 'sd'), + array('\'\'\'.*?\'\'\'', 'sd'), + ), $nonsemantic_rules, array( + array('[]{}:(),;[]', 'p'), + array('\\\\\\n', null), + array('\\\\', null), + array('(?:in|is|and|or|not)\\b', 'ow'), + array('(?:!=|==|<<|>>|[-~+/*%=<>&^|.])', 'o'), + array('(?:'.implode('|', $keywords).')\\b', 'k'), + array('def(?=\\s)', 'k', 'funcname'), + array('class(?=\\s)', 'k', 'classname'), + array('from(?=\\s)', 'kn', 'fromimport'), + array('import(?=\\s)', 'kn', 'import'), + array('(? array_merge($nonsemantic_rules, array( + array('[a-zA-Z_]\w*', 'nf', '!pop'), + array('', null, '!pop'), + )), + + 'classname' => array_merge($nonsemantic_rules, array( + array('[a-zA-Z_]\w*', 'nc', '!pop'), + array('', null, '!pop'), + )), + + 'fromimport' => array_merge($nonsemantic_rules, array( + array('import\b', 'kn', '!pop'), + // if None occurs here, it's "raise x from None", since None can + // never be a module name + array('None\b', 'bp', '!pop'), + // sadly, in "raise x from y" y will be highlighted as namespace too + array('[a-zA-Z_.][w.]*', 'nn'), + array('', null, '!pop'), + )), + + 'import' => array_merge($nonsemantic_rules, array( + array('as\b', 'kn'), + array(',', 'o'), + array('[a-zA-Z_.][w.]*', 'nn'), + array('', null, '!pop'), + )), + + 'dqs_raw' => $dqs, + 'sqs_raw' => $sqs, + 'dqs' => array_merge($stringescape, $dqs), + 'sqs' => array_merge($stringescape, $sqs), + 'tdqs_raw' => $tdqs, + 'tsqs_raw' => $tsqs, + 'tdqs' => array_merge($stringescape, $tdqs), + 'tsqs' => array_merge($stringescape, $tsqs), + + ); + } +} diff --git a/src/markup/syntax/engine/PhutilDefaultSyntaxHighlighterEngine.php b/src/markup/syntax/engine/PhutilDefaultSyntaxHighlighterEngine.php --- a/src/markup/syntax/engine/PhutilDefaultSyntaxHighlighterEngine.php +++ b/src/markup/syntax/engine/PhutilDefaultSyntaxHighlighterEngine.php @@ -78,6 +78,13 @@ ->getHighlightFuture($source); } + if ($language == 'py') { + return id(new PhutilLexerSyntaxHighlighter()) + ->setConfig('lexer', new PhutilPythonFragmentLexer()) + ->setConfig('language', 'py') + ->getHighlightFuture($source); + } + if ($language == 'invisible') { return id(new PhutilInvisibleSyntaxHighlighter()) ->getHighlightFuture($source);