/** * Tokenization rules setup */ public function setupRules() { parent::setupRules(); $this->rules->validator = new Validator(['!format.block.code', '!format.monospace', '!operator.escape', '!operator', '!tag']); $this->rules->addMany(['format.header' => [new Rule(new RegexMatcher('/^\\s{0,3}(#+.+?)\\r?$/m')), new Rule(new RegexMatcher('/^([^\\R]+?)^(?:-+|=+)\\R?$/m'))], 'format.italics' => new Rule(new RegexMatcher('/(?:^|[^*_])(?P<italics>(?P<i>[*_])(?>[^*_\\R]|(?:(?P<b>[*_]{2})(?>[^*_\\R]|(?&italics))*?\\g{b}))+\\g{i})/'), ['italics' => Token::NAME]), 'format.bold' => new Rule(new RegexMatcher('/(?P<bold>(?P<b>\\*\\*|__)(?>[^*_\\R]|(?:(?P<i>[*_]{2})(?>[^*_\\R]|(?&bold))*?\\g{i}))+\\g{b})/', ['bold' => Token::NAME])), 'format.strike' => new Rule(new RegexMatcher('/(~~.+?~~)/')), 'format.monospace' => [new Rule(new RegexMatcher('/(?:[^`]|^)(`.*?`)/')), new Rule(new RegexMatcher('/(``.*?``)/')), new Rule(new RegexMatcher('/^((?:(?: {4,}|\\t).*?(?>\\R|$)+?)+)/m'))], 'operator.list.ordered' => new Rule(new RegexMatcher('/^\\s*(\\d+[.)])/m')), 'operator.list.unordered' => new Rule(new RegexMatcher('/^\\s*([-+*])/m'), ['context' => ['none'], 'priority' => 1]), 'string.quote' => new Rule(new RegexMatcher('/((?:^>.*?\\R)+)/m')), 'format.block.code' => [new Rule(new DelegateRegexMatcher('/^```(.*?)\\R(.*?)\\R^```/ms', function ($match, TokenFactoryInterface $factory) { $lang = KeyLighter::get()->getLanguage($match[1][0]); (yield $factory->create(Token::NAME, ['pos' => $match[0][1], 'length' => strlen($match[0][0])])); (yield $factory->create("language.{$lang->getIdentifier()}", ['pos' => $match[2][1], 'length' => strlen($match[2][0]), 'inject' => $lang, 'class' => LanguageToken::class])); }), ['context' => Validator::everywhere(), 'postProcess' => true, 'priority' => 1000])], 'operator.escape' => new Rule(new RegexMatcher('/(\\\\.)/')), 'operator.horizontal' => new Rule(new RegexMatcher('/^\\s{,3}(([-*_])( ?\\2)+)\\R/m'), ['priority' => 2]), 'symbol.link' => new Rule(new RegexMatcher('/[^!](\\[(?:[^\\[\\]]|!\\[.*?\\]\\(.*?\\))*\\])/i')), 'symbol.url' => new Rule(new RegexMatcher('#(<(https?://|[^/])[-A-Za-z0-9+&@\\#/%?=~_|!:,.;]+[-A-Za-z0-9+&@\\#/%=~_|]>|https?://[-A-Za-z0-9+&@\\#/%?=~_|!:,.;]+[-A-Za-z0-9+&@\\#/%=~_|])#i'), ['priority' => 0]), 'symbol.image' => new Rule(new RegexMatcher('/(!)(\\[.*?\\])\\(.*?\\)/i', [1 => 'operator.image', 2 => '$.title']))]); }
protected function execute(InputInterface $input, OutputInterface $output) { $formatters = KeyLighter::get()->registeredFormatters(); $table = new Table($output); if (!$input->getOption('headerless')) { $table->setHeaders(['Name', 'Formatter']); } $table->setRows(array_map(function ($alias, $class) { return ["<comment>{$alias}</comment>", get_class($class)]; }, array_keys($formatters), array_values($formatters))); $table->setStyle($input->getOption('headerless') ? 'compact' : 'borderless'); $table->render(); }
protected function execute(InputInterface $input, OutputInterface $output) { $languages = KeyLighter::get()->registeredLanguages($input->getArgument('by'), $input->getOption('classes')); $table = new Table($output); if (!$input->getOption('headerless')) { $table->setHeaders([ucfirst($input->getArgument('by')), $input->getOption('classes') ? 'Class name' : 'Language']); } $table->setRows(array_map(function ($language) { return [implode(', ', array_map(function ($f) { return "<comment>{$f}</comment>"; }, $language['aliases'])), $language['class']]; }, $input->getOption('no-group') ? $this->processNonGrouped($languages) : $this->processGrouped($languages))); $table->setStyle($input->getOption('headerless') ? 'compact' : 'borderless'); $table->render(); }
/** * @param InputInterface $input * @param OutputInterface $output * @param $filename * @param $formatter */ protected function process(InputInterface $input, OutputInterface $output, $filename, $formatter) { $language = $input->getOption('language') ? KeyLighter::get()->getLanguage($input->getOption('language')) : Language::byFilename($filename); if (!($source = $this->content($filename))) { throw new InvalidArgumentException(sprintf('Specified file %s doesn\'t exist, check if given path is correct.', $filename)); } if ($output->isVerbose()) { $output->writeln(sprintf("Used file: <path>%s</path>, Language: <language>%s</language>, Formatter: <formatter>%s</formatter>", $filename, $language->getFQN(), get_class($formatter))); $verbose = new VerboseOutput($output, $input, $language, $formatter, $source); $formatted = $verbose->process(); } else { $formatted = KeyLighter::get()->highlight($source, $language, $formatter); } if (!$input->getOption('no-output')) { $output->writeln($formatted); } }
protected function generate() { $result = []; foreach (['name', 'mime', 'extension'] as $what) { foreach (KeyLighter::get()->registeredLanguages($what, true) as $name => $class) { $result[$class][$what][] = $name; } } $return = 'Class | Name | MIME | Extension' . PHP_EOL; $return .= '------|------|------|----------' . PHP_EOL; foreach ($result as $class => $aliases) { $return .= '`' . $class . '` | '; $return .= (isset($aliases['name']) ? '`' . implode('`, `', $aliases['name']) . '`' : 'none') . ' | '; $return .= (isset($aliases['mime']) ? '`' . implode('`, `', $aliases['mime']) . '`' : 'none') . ' | '; $return .= (isset($aliases['extension']) ? '`' . implode('`, `', $aliases['extension']) . '`' : 'none') . PHP_EOL; } return $return; }
function highlight($source, Language $language, FormatterInterface $formatter = null) { return KeyLighter::get()->highlight($source, $language, $formatter); }
public function testDefaultFormatter() { $this->assertInstanceOf(php_sapi_name() === 'cli' ? CliFormatter::class : HtmlFormatter::class, KeyLighter::get()->getDefaultFormatter()); }
public static function byFilename($filename, $params = []) { return KeyLighter::get()->languageByExt($filename, $params); }
public function testByFilename() { KeyLighter::get()->register(MockGreedyLanguage::class, ['extension' => ['*.mock']]); $this->assertInstanceOf(MockGreedyLanguage::class, Language::byFilename('file.mock')); }