Ce site a pour vocation de me présenter, moi, Hugo Vacher. Vous retrouverez ici mes créations, mon Curiculum Vitae. Se site comporte également une partie "blog" qui contiendras des conseils et ressources pour developpeurs.

PHPCommand v0.9 passons aux choses sérieuses !

Par Hugo Vacher | Catégories : Créations | Posté : 26-08-2009

1

Voila, après avoir découvert php -a qui fait pratiquement la même chose que PHPCommand v0.1 (Merci @paraboul), je me suis dit que mon script n’aurait aucun intérêt si je ne l’améliorais pas.

Voici donc un liste des amélioration de la version 0.9:

  • ATTENTION: ce script utilise des commandes Unix spécifique, il ne fonctionne donc plus windows.
  • Fonctionne sous Max OS X, et sur la plupart des distributions linux (support des « VT220 terminal escape sequences » et des commandes stty et dd nécessaire).
  • Support de l’historique, utilisez les touches haut et bas pour naviguer dans l’historique.
  • Support de la navigation horizontale pour corriger/inserer des caracteres, support des touches Del et Ret arrière.
  • Si votre script affiche un message ne se términant pas par « \n » celui-ci est ajouté automatiquement.

Todo list:

  • Ajouter l’aide avec F1 et avec –help
  • Naviguer avec la souris
  • Coloration syntaxique (merci @un_geek) ?
  • D’autres idées ?

Voila le nouveau code (beaucoup plus long, ici on gere tout à la main (position du curseur, gestion des touches etc…):

#! /usr/bin/php
<?php
/**
 * Class used to isolate functions and vars that needs to keep defined while
 * evaluating users code.
 */
class PHPc{
 
  const PROMPT = 'php>';
  const PSIZE = 5;//Prompt's size +1
 
  public static $lines = array();
  public static $code_to_eval;
  public static function readChar(){
    $ret = exec('stty cbreak -echo;c=`dd bs=1 count=1 2>/dev/null`;stty -cbreak echo;echo "$c."');
    if($ret=='.') return "\n";
    return substr($ret, 0, 1);
  }
  public static function delChar(&$line, $pos){
    $line = substr($line, 0, $pos).substr($line, $pos+1);
  }
  public static function setLine(&$from, $to){
    $size = strlen($from);
    $goto = strlen($to)+self::PSIZE;
    echo "\033[".self::PSIZE."G\033[{$size}P{$to}\033[{$goto}G";
    $from = $to;
    return $goto;
  }
}
echo <<<INTRO
PHP Command 0.9 Created by Hugo Vacher (korri.fr)
 
Code is interpreted when line end with ';' or '}' and that all '{' are closed.
 
You are free to use, modify and redistribute this code, please leave me a comment if you do it.
 
INTRO;
 
  while(true){
    PHPc::$code_to_eval = '';
    $continue = true;
    while($continue){
      //Reset history index
      $index = 0;
      //Say that line isn't finished
      $ln = true;
      //Reset cursor pos
      $c = PHPc::PSIZE;
      $total = PHPc::PSIZE;
 
      $line = '';
      echo PHPc::PROMPT;
      //Add empty line
      array_unshift(PHPc::$lines, '');
 
      while($ln){
        $char = PHPc::readChar();
        $cod = ord($char);
 
        //Gonna parse each key
        if($cod == 10){//Enter
          echo "\033[".PHPc::PSIZE."G\n";
          $ln = false;
        }else if($cod == 127){//Ret arriere
          if($c > PHPc::PSIZE){
            PHPc::delChar($line, --$c-PHPc::PSIZE);
            --$total;
            echo "\033[D\033[1P";
          }
        }else if($cod == 4){//Ctrl + D
          break 3;//We exit programm
        }else if($cod == 27){
          $key = PHPc::readChar().PHPc::readChar();
          switch($key){
            case '[3'://Del
              PHPc::readChar();
              if($c < $total){
                PHPc::delChar($line, $c-PHPc::PSIZE);
                --$total;
                echo "\033[1P";
              }
              break;
            case '[A'://up
              if(isset(PHPc::$lines[$index+1])){
                if($index==0) PHPc::$lines[0] = $line;
                $to = PHPc::$lines[++$index];
                $c = PHPc::setLine($line, $to);
                $total = $c;
              }
              break;
            case '[B'://down
              if($index > 0){
                $to = PHPc::$lines[--$index];
                $c = PHPc::setLine($line, $to);
                $total = $c;
              }
              break;
            case '[D'://left
              if($c > PHPc::PSIZE) echo "\033[".--$c.'G';
              break;
            case '[C'://right
              if($c<$total) echo "\033[".++$c.'G';
              break;
            default:
              //We don't do nothing, here we'll handle F1 key
          }
        }else{
          echo "\033[4h$char\033[4l";//Echo char in insert mode
		  //Get the 2 next chars (special keys are at least 3chars
          $line  = substr($line, 0, $c - PHPc::PSIZE);
		  $line .= $char.substr($line, $c - PHPc::PSIZE);
          ++$c; ++$total;
        }
      }
      PHPc::$lines[0] = $line;
      PHPc::$code_to_eval .= $line;
      if(substr($line,-1)==';' || substr($line,-1)=='}'){
        $cnto = substr_count(PHPc::$code_to_eval, '{');
        $cntc = substr_count(PHPc::$code_to_eval, '}');
 
        if($cntc >= $cnto){
          $continue = false;
        }
      }
    }
    //Clear local vars
    unset($c, $total, $line, $continue, $char, $cod, $cnto, $cntc, $to, $index);
 
    ob_start();
    eval(PHPc::$code_to_eval);
    $txt = ob_get_contents();
    ob_end_flush();
    if($txt!='' && substr($txt, -1) != "\n") echo "\n";
  }
  echo "\nExit\n";
?>

Le code seul ici: phpc.php

PS: Je ferais une version plus propre et mieux documentée, quand je sortirais la 1.0, pour le moment ce code n’a qu’un but utilitaire et non un but d’apprentissage.

Commentaires (1)

[...] EDIT: Retrouvez la nouvelle version ici : PHPCommand 0.9 [...]

Laisser un commentaire