[addon todopanel] TodoPanel
- Mikulas Dite
- Člen | 756
No problém je v tom panelu, ale nevíme kde, protože je problém v Nette. Tzn. zkusím zjistit, proč tohle nezachytává Laděnka a potom se uvidí.
- thool
- Člen | 6
WOOOHOOO!
Podařilo se mi tohle rozjet na prefixovém nette 2.0-beta – PHP 5.2
změny:
- záměna funkcí
callback($this, "xxxx")
zaArray($this, "xxxx")
- dále oddělání jmenných prostorů
- přidání prefixů
- přejmenování třídy
- záměna
$ignoreMask ?: array( ...
na($ignoreMask) ? $ignoreMask : array( ...
použití:
v bootstrap.php přidat řádek:
TodoPanel::register( $container->params['appDir'] );
Na to jaký jsem Nette neználek si teď připadám jak nějaký guru :-)
<?php
/**
* TodoPanel for Nette 2.0
*
* @author Mikuláš Dítě, Peter Ped Helcmanovsky
* @license MIT
*/
/* //PHP 5.3
namespace Panel;
use Nette\Diagnostics\Debugger;
use Nette\Utils\Finder;
use Nette\Diagnostics\IBarPanel;
use Nette\Object;
use Nette\Utils\SafeStream;
use Nette\Utils\Strings as String;
use Nette\Templating\FileTemplate;
use Nette\Latte\Engine;
class Todo extends Object implements IBarPanel
*/
class TodoPanel extends NObject implements IBarPanel
{
/** @var array|mixed stores found todos */
private $items = array();
/** @var array */
private $scanDir = array();
/** @var array any path or file containing one of the patterns to skip */
private $ignoreMask = array();
/** @var array */
private $commentBlockMask = array();
/** @var array patterns for "todo" comments to catch */
public $todoMask = array('TO\s?DO', 'FIX\s?ME', 'PENDING', 'XXX');
/** @var bool defines wheter the todo type should be visible */
public $showType = FALSE;
/**
* @param array|string $basedir path or paths to scan
* @param array $ignoreMask can use wildcards
*/
public function __construct($basedir, $ignoreMask = NULL)
{
if (is_array($basedir)) {
foreach ($basedir as $path) {
$this->addDirectory(realpath($path));
}
} else {
$this->addDirectory(realpath($basedir));
}
$this->setIgnoreMask( ($ignoreMask) ? $ignoreMask : array('.git', '.svn', 'cache', 'log', 'sessions', 'temp'));
$patterns = array(
array('~^(php|css|js)$~', '~/\*(?P<content>.*?)\*/~sm'),
array('~^(php|js)$~', '~//(?P<content>.*?)$~sm'),
array('~^(php|sh|ps1)$~', '~#(?P<content>.*?)$~sm'),
array('~^(latte|phtml)$~', '~{\*(?P<content>.*?)\*}~sm'),
array('~^(latte|phtml|html)$~', '~<!--(?P<content>.*?)-->~sm'),
array('~^(ini)$~', '~;(?P<content>.*?)$~sm'),
array('~^(bat)$~', '~^[ \t]*REM[ \t]+(?P<content>.*?)$~smi'),
);
foreach ($patterns as $pattern) {
call_user_func_array( Array($this, 'addPattern'), $pattern);
}
}
/**
* Renders HTML code for custom tab
* IDebugPanel
* @return void
*/
public function getTab()
{
return '<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAPnRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBUaGUgR0lNUAoKKGMpIDIwMDMgSmFrdWIgJ2ppbW1hYycgU3RlaW5lcicz71gAAAGtSURBVHjarZMxSBthFMd/d/feqVjiIAoFcQqVFoogjUSJdDBYaECH4Nq1OLiU2C52KKGi4uTgEhDcFRxEyeDSsQdKhdKSEhAFseEGCxFpa+7r0Fi8axM7+OC/vf/ve+//+ODftQKYiFa4ofLXDb7v/1GpVIrC8lcmuQaYLSzMcPDlhM2dXTzPo1KpAFAul7nb3clo6hEDD/t48WZ5FngdBQCwWXzH1naRarVKLBYDIB6PY9s2hUKBs69Hof4QwBjIZrOkUqlQk2VZAORyOYobq40BYMhknjI+PoGqIFKXKuoIjgrF9aYAEHERdVDRullQR2ibew73+jHGhPrt8PugKrC2RPv8FHv7e3jvPdpeTWKdHuP0D/11uhAgCMB1XXrK+7SffyORSPB4fRHr4hx7+i1uMk0QNJvAGEQVv/c+Vu2Sjpks+vM79vQcLck0qtp8hVoQoKp4gxP4vQ+wapccjEzSOpxGXEVFCCKAcIjG4Kow9mQMzWQQEZKiqApO/SIYGgMCA0svn/H5sIKpZxJ1xO60NgZ8+viB6sUPero6+J2VITLx/3+mG5TntuoX7nmiqfg2Y6EAAAAASUVORK5CYII=">' .
'Todo (' . $this->getTodoCount() . ')';
}
/**
* Renders HTML code for custom panel
* IDebugPanel
* @return void
*/
public function getPanel()
{
ob_start();
$template = new NFileTemplate(dirname(__FILE__) . '/bar.todo.panel.latte');
$template->registerFilter(new NLatteFilter());
$template->todos = $this->getTodo();
$template->todoCount = $this->getTodoCount();
$template->showType = $this->showType;
$template->render();
return ob_get_clean();
}
/**
* IDebugPanel
* @return string
*/
public function getId()
{
return __CLASS__;
}
/**
* Registers panel to Debug bar
*/
public static function register($basedir = NULL, $ignoreMask = NULL)
{
NDebugger::addPanel(new self($basedir, $ignoreMask));
}
/**
* Add directory to list
* @param string
* @return void
* @throws DirectoryNotFoundException
*/
public function addDirectory($path)
{
$realpath = realpath($path);
if (!$realpath) {
throw new NDirectoryNotFoundException("Directory `$path` not found.");
}
if (!array_search($realpath, $this->scanDir)) {
$this->scanDir[] = $realpath;
}
}
/**
* Adds custom comment block pattern
* @param string $extension regex
* @param string $pattern regex Must contain group named `content`
*/
public function addPattern($extension, $pattern)
{
self::validatePattern($pattern);
$this->commentBlockMask[] = array('extension' => $extension, 'pattern' => $pattern);
}
/**
* Throws exception if custom pattern does not name comment block content group
* @example pattern `~block_start(?P<content>.*?)block_end~sm`
* @throws \InvalidArgumentException
* @param string $pattern regex
*/
private static function validatePattern($pattern)
{
if (NStrings::match($pattern, '~\\(\\?P<content>\\.\\*\\?\\)~') === NULL) {
throw new NInvalidArgumentException('Custom pattern `' . $pattern . '` does not contain a group named `content`.');
}
}
/**
* Files to ignore
* @example $todoPanel->setIgnoreMask(array('.git', 'app/sessions'));
* @param array $ignoreMask
*/
public function setIgnoreMask(array $ignoreMask, $merge = FALSE)
{
if ($merge) {
foreach ($ignoreMask as $mask) {
if (!array_search($mask, $this->ignoreMask)) {
$this->ignoreMask[] = $mask;
}
}
} else {
$this->ignoreMask = $ignoreMask;
}
}
/**
* Sum of found todos in browsed files
* @return int
*/
public function getTodoCount()
{
$count = 0;
foreach ($this->getTodo() as $file) {
$count += count($file);
}
return $count;
}
/**
* usort implementation
* @param array $compared
* @param array $todo
* @return int
*/
public function compareTodos($compared, $todo)
{
if ($compared['line'] == $todo['line']) {
return 0;
}
return $compared['line'] < $todo['line'] ? -1 : 1;
}
/**
* Wrapper for generateTodo, performace booster in one instance
*/
private function getTodo()
{
if (empty($this->items)) {
$this->items = $this->generateTodo();
}
return $this->items;
}
/**
* Returns array in format $filename => array($todos)
* @uses \Nette\SafeStream
* @throws \Nette\InvalidStateException
*/
private function generateTodo()
{
if (count($this->todoMask) === 0) {
throw new NInvalidStateException('No todo mask specified for TodoPanel.');
}
@NSafeStream::register(); //intentionally @ (prevents multiple registration warning)
$items = array();
foreach (NFinder::findFiles('*')->size('> 3B')->exclude('.*', '*/' . $this->ignoreMask . '/*')->from($this->scanDir) as $path => $file) {
$items[$path] = $this->parseFile($file);
}
return $items;
}
/**
* Reads pointed file and returns all comments found
* @param SplFileInfo $file
* @returns array
*/
private function parseFile($file)
{
$todos = array();
$stream = fopen("safe://" . $file->getRealPath(), 'r');
$content_original = $content = fread($stream, filesize("safe://" . $file->getRealPath()));
fclose($stream);
// Remove harcoded strings so we do not search in them
$content = NStrings::replace($content, '~("|\')(.|\\\"|\\\')*?("|\')~s', '\'\'');
$patterns = array();
foreach ($this->commentBlockMask as $pattern) {
if (NStrings::match(pathinfo($file, PATHINFO_EXTENSION), $pattern['extension'])) {
$patterns[] = $pattern['pattern'];
}
}
$matches = array();
// find block comments
foreach ($patterns as $pattern) {
$matches = array_merge($matches, NStrings::matchAll($content, $pattern));
$content = NStrings::replace($content, $pattern);
}
$comment_lines = array();
// split block comments by lines
foreach ($matches as $match) {
$comment_block = NStrings::trim($match['content']);
$comment_lines = array_merge($comment_lines, NStrings::split($comment_block, '~[\r\n]{1,2}~'));
}
foreach ($comment_lines as $key => $comment_content) {
$match = NStrings::match($comment_content, '~(^[@*\s-]*|[@*\s-])(?P<type>' . implode('|', $this->todoMask) . ')\s+(?P<todo>.*?)$~mi');
if ($match === NULL) {
continue;
}
$skip = 0;
foreach ($comment_lines as $tkey => $line) {
if ($tkey >= $key) {
break;
}
if ($line == $comment_content) {
$skip++;
}
}
$line = 0;
// assign line number
foreach (NStrings::split($content_original, '~\n~') as $line_number => $content_line) {
if (strpos($content_line, $comment_content) !== FALSE) {
if ($skip > 0) {
$skip--;
continue;
}
$line = $line_number + 1;
break;
}
}
$todos[] = array(
'line' => $line,
'type' => NStrings::lower($match['type']),
'content' => $match['todo'],
'link' => strtr(NDebugger::$editor, array('%file' => urlencode($file->getRealPath()), '%line' => $line)),
'file' => $file->getFilename(),
);
}
usort($todos, Array($this, 'compareTodos'));
return $todos;
}
}
// nazev tridy poupraven
Editoval thool (18. 8. 2011 15:44)
- Mikulas Dite
- Člen | 756
Fajn, akorát prefix I
značí interface, což ta třída není
:). Takže když už, tak BarTodo
(a ještě lépe
TodoPanel
).
- Marax
- Člen | 28
Darkry napsal(a):
a server mi při načítání stránky vyhodí:Tato webová stránka není dostupná. Chyba 101(net::ERR_CONNECTION_RESET): Připojení bylo resetováno.
Přitom funkce register() se vykoná, protože pokud v ní udělám chybu hodí mi to laděnku.
Taky se mi už několikrát stala chyba 101 a vždycky nějak záhadně zmizela po tom co jsem se v tom dobu šťoural. Až teď jsem zjistil,že to bylo tímhle doplňkem.
Dal jsem si logovat všechny soubory na začátku a konci metody parseFile a jediný který neprošel a na kterém to skončilo byl config.neon.
Pokud v neonu smažu všechny komentáře tak to jde.
- Matúš Matula
- Člen | 257
Rovnaka chyba 101 aj u mna, blizsie sa mi ale nepodarilo zistit, co ju sposobuje :/
Mikulas Dite napsal(a):
No problém je v tom panelu, ale nevíme kde, protože je problém v Nette. Tzn. zkusím zjistit, proč tohle nezachytává Laděnka a potom se uvidí.
Ziadny pokrok ani u teba?
- Matúš Matula
- Člen | 257
Pouzivam tak, ako je v dokumentacii, teda
<?php
\Panel\Todo::register($this->context->params['appDir'], array('.git', '.svn', 'cache', 'log', 'sessions', 'temp', 'config', '*.neon', ));
?>
- dada-amater
- Bronze Partner | 52
Neplanujes moznost instalace pres Composer? Bylo by to moc fajn. Dik