<?php
namespace Tlf\Bash\Scrawl;
/**
* Generates help menus for bash libraries
*/
class HelpMenuGenerator extends \Tlf\Scrawl\DoNothingExtension {
protected $regexes = [
'function' => '/\ *function\ *([a-zA-Z\_].+)\(\)/'
];
protected $funcList = [];
/**
*
*/
public function scan_file_processed(string $path, string $relPath, string $file_content, array $file_exports){
if (!$this->is_core_file($path))return;
echo "Get ast for $path";
$ast = $this->get_bash_ast($path);
if (($count=count($ast['function']??[]))==0){
$this->scrawl->warn("No functions", "No functions found in file '$relPath'");
return;
}
$this->scrawl->good("\nBash Ast", "Found $count functions in file '$relPath'");
// add the ast to the output
foreach ($ast['function'] as $func){
// add all functions to `bash_function` group
$this->scrawl->set('bash_function', $func['name'], $func);
// add function to `bent_function` group if it can be executed through cli by the user
// so if a file is `core-whatever.bash` and the function is `core_something(){}`, it fits in the `core` group.
$file = basename($relPath);
$name = $func['name'];
$parts = explode("_", $name);
$group = $parts[0];
if (substr($file,0,strlen($group))==$group){
$this->scrawl->set('bent_function', $func['name'], $func);
}
}
}
/**
* Generate help menus
*/
public function scan_filelist_processed(array $code_files, array $all_exports){
$bent_functions_flat = $this->scrawl->get_group('bent_function');
$grouped_functions = $this->group_bent_functions($bent_functions_flat);
$mains = $grouped_functions['-main-'];
unset($grouped_functions['-main-']);
$mains_menu = $this->generate_main_help_menu($mains);
$this->scrawl->write_file('code/help/help_groups.bash', $mains_menu);
foreach ($grouped_functions as $group=>$functions){
$help_menu = $this->generate_help_menu($group, $functions);
$this->scrawl->write_file('code/help/'.$group.'.bash', $help_menu);
}
}
/**
* Generate a string that shows a help menu using the bash cli
* @param $group the group name
* @param $functions an array of functions
*/
public function generate_help_menu(string $group, array $functions){
$help_command = "prompt_choose_function \"# $group [command]\${cOff}-\" ";
foreach ($functions as $function){
$help_command .= " \\\n";
$name_parts = explode("_", $function['name']);
if (count($name_parts)==1){
$command = '-default-';
$command_run = '';
}
else {
array_shift($name_parts);
$command = implode(' ',$name_parts);
$command_run = $command;
}
$description_full = $function['docblock']['tip'] ?? $function['docblock']['description'] ?? '';
$parts = explode("\n", trim($description_full));
$description = trim($parts[0]);
if ($description=='')$description = '-- no description';
$help_command .= "\"\${help_mode} $command_run\" \"$command\" \"$description\"";
}
return $help_command;
}
public function generate_main_help_menu(array $functions){
$help_command = "prompt_choose_function \"# [command]\${cOff}-\" ";
foreach ($functions as $function){
$help_command .= " \\\n";
$command = $function['name'];
$command_run = $function['name'];
$description_full = $function['docblock']['tip'] ?? $function['docblock']['description'] ?? '';
$parts = explode("\n", trim($description_full));
$description = trim($parts[0]);
if ($description=='')$description = '-- no description';
$help_command .= "\"\${help_mode} $command_run\" \"$command\" \"$description\"";
}
return $help_command;
}
/**
* Group functions by their group. i.e. `core_something()` goes into `core`. `test_whatever` goes into `test`
*
* @param $bent_functions_flat array of all bent functions to group
* @return array with @key=group_name & @value=array of functions in that group. Also contains `-main-` which is commands with only one part (no underscores).
*/
public function group_bent_functions(array $bent_functions_flat){
/** -main- is all the main commands like `core`, `test`, and whatever */
$bent_functions_grouped = ['-main-'=>[]];
foreach ($bent_functions_flat as $function){
$name = $function['name'];
$parts = explode("_", $name);
$group = $parts[0];
if (count($parts)==1)$bent_functions_grouped['-main-'][$group] = $function;
else if (!isset($bent_functions_grouped['-main-'][$group])){
$bent_functions_grouped['-main-'][$group] = ['name'=>$group];
}
if (!isset($bent_functions_grouped[$group])) $bent_functions_grouped[$group] = [];
$bent_functions_grouped[$group][] = $function;
}
return $bent_functions_grouped;
}
/**
* Get an ast
* @param $file_path absolute path to the file to aprse
* @return array of the generated ast
*/
public function get_bash_ast(string $file_path){
$lexer = new \Tlf\Lexer();
$bashGrammar = new \Tlf\Lexer\BashGrammar();
$lexer->addGrammar($bashGrammar, null, false);
// $lexer->addGrammar($bashGrammar, 'this', false);
foreach ($bashGrammar->getDirectives(':bash') as $directive){
$lexer->addDirective($directive);
}
$startingAst = new \Tlf\Lexer\Ast('file', []);
$ast = $lexer->lex(file_get_contents($file_path),$startingAst);
$tree = $ast->getTree();
return $tree;
}
/**
* Check if the target file is in the `code/core` dir and has a `.bash` extension
*/
public function is_core_file($path){
if (pathinfo($path,PATHINFO_EXTENSION)!='bash')return false;
$dir = dirname($path);
if (substr($dir,-strlen('/code/core'))!='/code/core')return false;
return true;
}
/**
*
* old help file generation ...
* it's a mess
*
*
* keep this around until the rest the code is processed out of it. Primarily, that is the `uasort()` that uses docblock attribute @order to order items in the help menu. Second is the generation of a help menu that shows all the command groups.
*
* There might need to be additional changes/improvements to the help menu generation ... idunner.
*/
public function old_scan_filelist_processed(array $code_files, array $all_exports){
// print_r($this->scrawl->getOutputs('function'));
// exit;
$funcs = $this->scrawl->get_group('bash_function');
// print_r(array_keys($funcs));
// exit;
$byGroup = [];
foreach ($funcs as $f){
$parts = explode('_', $f['name']);
$group = $parts[0];
// if ($group!='log')continue;
if ($group==$f['name'])$byGroup[$group]['main']=$f;
else $byGroup[$group][] = $f;
}
// print_r(array_keys($byGroup));
// exit;
$mains = [];
/** Generate help menu for each command group
*/
foreach ($byGroup as $group => $list){
$help = [];
if (!isset($list['main'])){
// var_dump($group);
// var_dump($list);
// exit;
// continue;
$list['main'] = [
'type'=>'function',
'name'=>$group,
'docblock'=>[
'type'=>'docblock',
'src'=>'--',
'description'=>'--',
],
];
}
$f = $list['main'];
// var_dump($f);
// exit;
unset($list['main']);
array_unshift($list,$f);
$mains[$f['name']] = $f;
$descript = $f['docblock']['tip'] ?? $f['docblock']['description'] ?? '';
$help[] = "# [bent $group] \${cOff}- $descript";
// if ($group=='log'){
// print_r($f);exit;
// }
foreach ($list as $function){
// "run core check" "check" "Check the status of your project"
// if (($function['docblock']??null)==null){
// $function['docblock']['']
// continue;
// }
$parts = explode('_', $function['name']);
$help[] = '${help_mode} '.implode(" ", $parts);
$help[] = implode(" ", count($parts)>1 ? array_slice($parts,1) : $parts);
$help[] = $function['docblock']['tip'] ?? $function['docblock']['description'] ?? '';
}
$help = array_map(function($v){return "\"$v\"";}, $help);
$helpStr ='prompt_choose_function '.implode(" ", $help);
// $this->scrawl->addOutput('file', '../code/help/'.$group.'.bash', $helpStr);
$this->scrawl->write_file('code/help/'.$group.'.bash', $helpStr);
}
uasort($mains,
function($a, $b){
$orderA = (int)($a['docblock']['order'] ?? 9999);
$orderB = (int)($b['docblock']['order'] ?? 9999);
if ($orderA > $orderB)return 1;
else if ($orderA == $orderB)return 0;
else return -1;
},
);
// print_r($mains);
// exit;
/** Generate help menu for [bent help] */
$help = [];
unset ($mains['']);
// $helpFunc = $mains['help'];
// unset($mains['help']);
// $help[] = "# ".($helpFunc['docblock']['description'] ?? $helpFunc['docblock']['tip'] ?? '');
foreach ($mains as $name=>$function){
$parts = explode('_', $function['name']);
$help[] = '${help_mode} '.implode(" ", $parts);
$help[] = implode(" ", array_slice($parts, 0,1));
$help[] = $function['docblock']['tip'] ?? $function['docblock']['description'] ?? '';
}
$help = array_map(function($v){return "\"$v\"";}, $help);
$helpStr = 'prompt_choose_function '.implode(" ", $help);
// $this->scrawl->addOutput('file', '../code/help/help_groups.bash', $helpStr);
$this->scrawl->write_file('code/help/help_groups.bash', $helpStr);
}
}