1, ]; } /** @inheritdoc */ protected function getSyntaxKeyword(): string { return 'directory'; } /** @inheritdoc */ public function connectTo($mode) { // Accept both {{directory>...}} and {{files>...}} for backwards compatibility $this->Lexer->addSpecialPattern('\{\{directory>.+?\}\}', $mode, 'plugin_luxtools_directory'); $this->Lexer->addSpecialPattern('\{\{files>.+?\}\}', $mode, 'plugin_luxtools_directory'); } /** @inheritdoc */ public function handle($match, $state, $pos, Doku_Handler $handler) { // Detect which keyword was used $keyword = 'directory'; if (str_starts_with($match, '{{files>')) { $keyword = 'files'; } $match = substr($match, strlen('{{' . $keyword . '>'), -2); [$path, $flags] = array_pad(explode('&', $match, 2), 2, ''); $params = $this->parseFlags($flags); $pathData = $this->processPath($path); // Store the original keyword to determine processing mode $pathData['isGlobPattern'] = ($keyword === 'files'); return ['pathData' => $pathData, 'params' => $params]; } /** @inheritdoc */ protected function processPath(string $path): array { // Check if path contains glob characters (*, ?, [, ]) $hasGlob = (str_contains($path, '*') || str_contains($path, '?') || str_contains($path, '[') || str_contains($path, ']')); if ($hasGlob) { // Process as glob pattern (old files syntax) [$base, $pattern] = $this->separatePathAndPattern($path); return ['base' => $base, 'pattern' => $pattern, 'isGlobPattern' => true]; } else { // Process as directory path $path = Path::cleanPath($path, true); return ['path' => $path, 'isGlobPattern' => false]; } } /** @inheritdoc */ protected function doRender(string $format, \Doku_Renderer $renderer, array $pathData, array $params): bool { $isGlobPattern = $pathData['isGlobPattern'] ?? false; if ($isGlobPattern && isset($pathData['base'], $pathData['pattern'])) { // Old files syntax behavior: crawl with glob pattern $pathInfo = $this->getPathInfoSafe($pathData['base'], $renderer); if ($pathInfo === false) { return true; } $crawler = $this->createCrawler($params); $result = $crawler->crawl( $pathInfo['root'], $pathInfo['local'], $pathData['pattern'], $params['recursive'], $params['titlefile'] ); // Pass the base directory as openlocation so the "Open Location" link is displayed. $params['openlocation'] = $pathInfo['root'] . $pathInfo['local']; $output = new Output($renderer, $pathInfo['root'], $pathInfo['web'], $result, $this); $output->renderAsTable($params); } else { // Normal directory listing behavior $pathInfo = $this->getPathInfoSafe($pathData['path'], $renderer); if ($pathInfo === false) { return true; } // Provide the current directory path so Output can render the "Open Location" link. $params['openlocation'] = $pathInfo['root'] . $pathInfo['local']; $crawler = $this->createCrawler($params); $items = $crawler->listDirectory( $pathInfo['root'], $pathInfo['local'], $params['titlefile'] ); // Render the table even if empty so the "Open Location" link is displayed. $output = new Output($renderer, $pathInfo['root'], $pathInfo['web'], $items, $this); $output->renderAsFlatTable($params); } return true; } }