2017-09-22 7 views
1

J'écris un Lisp minimal avec un projet d'environnement REPL basé sur un terminal classique dans Rust. Comment lire l'entrée utilisateur à l'aide des touches fléchées, en leur permettant d'avancer et de reculer sur leur ligne d'entrée actuelle au moins avant d'avoir appuyé sur enter? Idéalement, je serai en mesure d'étendre les fonctionnalités pour inclure "revenir" pour récupérer les anciennes entrées comme vous le feriez dans n'importe quel terminal ou REPL. Voici une image du comportement pour plus de clarté:Comment activer l'entrée utilisateur modifiable pour une application de terminal Rust?

enter image description here

J'ai joué avec le module de bibliothèque standard io et la caisse termion mais n'ont pas compris cette fonctionnalité out.

Voici mon code de travail actuel. Il prend effectivement en entrée et l'imprime immédiatement à l'utilisateur en plus de quitter comme prévu avec quit().

use std::io::prelude::*; 
use std::io; 

fn main() { 
    println!("Rispy Version 0.0.1"); 
    println!("Enter `quit()` to Exit"); 

    let mut input: String; 

    // continuous input til ctrl-c or quit() 
    loop { 

     print!("rispy>> "); 
     io::stdout().flush().unwrap(); 

     input = String::new(); 
     io::stdin().read_line(&mut input) 
      .expect("Error reading line"); 

     print!("input: {}", input); 

     match input.as_ref() { 
      "quit()\n" => { 
       println!("\nGoodbye"); 
       break; 
      }, 
      _ => continue, 
     } 
    } 
} 
+3

La manière la plus simple serait d'utiliser une caisse existante. Par exemple, [readline] (https://crates.io/crates/readline) encapsule GNU readline, ou [rustyline] (https://crates.io/crates/rustyline) est une implémentation de rouille. – kazemakase

+1

@kazemakase Voici la réponse. Vous devriez le poster comme une réponse réelle. – Boiethios

+2

@Boiethios J'hésite à publier des liens vers des bibliothèques comme réponses parce que cela pourrait impliquer que la question est hors-sujet, bien qu'allumer une bibliothèque n'était pas l'intention du PO ... La façon dont j'ai lu la question du PO pourrait en fait * veulent * l'implémenter eux-mêmes. – kazemakase

Répondre

3

Il est drôle comment certaines caisses de base/fondamentaux ne sont pas proposées ailleurs plus facilement des problèmes comme celui-ci, mais heureusement @kazemakase répondu à la question en suggérant une caisse que je ne l'avais pas trouvé jusqu'à ce point: rustyline

A légère modification à l'exemple de code sur le readme donne les résultats que je veux, avec l'histoire, la possibilité de naviguer à gauche/droite avec les touches fléchées, et même l'utilisation de touches comme ctrl-d, ctrl-c, home, etc. Ici, il est à coupler avec la question posée:

extern crate rustyline; 

use rustyline::Editor; 
use rustyline::error::ReadlineError; 

fn main() { 
    println!("Rispy Version 0.0.1"); 
    println!("Enter `quit()` to Exit"); 

    let mut reader = Editor::<()>::new(); 
    if let Err(_) = reader.load_history("rispy_history.txt") { 
     println!("No previous history."); 
    } 

    // continuous input 
    loop { 

     let readline = reader.readline("rispy>> "); 

     match readline { 
      Ok(line) => { 
       reader.add_history_entry(&line); 
       println!("input: {}", line); 
      }, 
      Err(ReadlineError::Interrupted) => { 
       println!("CTRL-C"); 
       println!("Goodbye"); 
       break 
      } 
      Err(ReadlineError::Eof) => { 
       println!("CTRL-D"); 
       println!("Goodbye"); 
       break 
      }, 
      Err(err) => { 
       println!("Error: {:?}", err); 
       break 
      } 
     } 
    } 
    reader.save_history("rispy_history.txt").unwrap(); 
} 
+0

Content d'avoir entendu mon commentaire était utile. Vous pouvez accepter votre propre réponse si vous pensez que c'est la meilleure solution à votre problème. – kazemakase

2

En réponse hors-the-box, je l'utilise de temps en temps rlwrap, une petite enveloppe autour tout programme de ligne de commande qui ajoute des capacités readline de base.

En cours d'exécution rlwrap cargo run, votre programme d'origine est maintenant édité comme vous l'avez demandé, ainsi que l'historique des commandes et la recherche historique, et probablement beaucoup d'autres choses.

+0

Je pense que c'est une bonne réponse et je suis également étonné par le fait que je ne connaissais pas de solutions proches de cette réalité.Cela dit, je suis en train de choisir ma réponse (fournie par @kazemakase dans les commentaires) comme la solution car elle répond au problème à l'intérieur du programme plutôt qu'en dehors de celui-ci comme je l'ai demandé. – zaile