Aucune description
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

shell.rs 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. use std::io::{BufRead, Write, Read, StdinLock, StdoutLock};
  2. use std::io;
  3. use command::*;
  4. use std::str::FromStr;
  5. use std::env;
  6. ///Tuple-Structs which hold Std-in and -out locks.
  7. pub struct R<'a>(pub StdinLock<'a>);
  8. pub struct W<'a>(pub StdoutLock<'a>);
  9. pub struct Shell<R, W> {
  10. pub reader: R,
  11. pub writer: W,
  12. pub should_exit: bool,
  13. pub name: String,
  14. }
  15. impl<'a> Shell<R<'a>, W<'a>> {
  16. /// Creates a new Shell with a name, input and output.
  17. pub fn new(input: R<'a>, output: W<'a>, name: String) -> Self {
  18. Shell {
  19. reader: input,
  20. writer: output,
  21. should_exit: false,
  22. name: name,
  23. }
  24. }
  25. /// Initializes the Shell Loop.
  26. /// Starts the shell.
  27. pub fn start(&mut self) -> Result<(), &str> {
  28. self.shell_loop()
  29. }
  30. /// Loops while exit hasn't been called.
  31. /// When *prompt()* returns (the user hit enter) a Command is created through the FromStr-Trait.
  32. /// If the Command-creation succeeds, run the command.
  33. fn shell_loop(&mut self) -> Result<(), &str> {
  34. while !self.should_exit {
  35. if let Ok(line) = self.prompt() {
  36. let _ = Command::from_str(&line).and_then(|cmd| self.run(cmd));
  37. }
  38. }
  39. Ok(())
  40. }
  41. /// Prints the shell prompt.
  42. /// Waits for user input and returns the read line.
  43. fn prompt(&mut self) -> Result<String, &str> {
  44. match env::current_dir() {
  45. Ok(pwd) => {
  46. let _ = self.writer.write(
  47. format!("{} {} > ", self.name, pwd.display())
  48. .as_bytes(),
  49. );
  50. let _ = self.writer.flush();
  51. let mut line: String = String::new();
  52. let read_result = self.reader.read_line(&mut line);
  53. match read_result {
  54. Ok(_) => Ok(line),
  55. Err(_) => Err("Error reading."),
  56. }
  57. }
  58. Err(_) => return Err("Path Error"),
  59. }
  60. }
  61. /// Runs a command.
  62. /// Currently only `cd` and `exit` are working.
  63. fn run(&mut self, command: Command) -> Result<(), CommandNotFoundError> {
  64. match command {
  65. Command::Empty => {}
  66. Command::Exit => self.should_exit = true,
  67. Command::Cd(_) => {
  68. command.exec_cd();
  69. }
  70. }
  71. Ok(())
  72. }
  73. }
  74. /// Implement Read-Trait for Tuple-Struct R
  75. /// Simply calls `read` of StdinLock
  76. impl<'a> Read for R<'a> {
  77. fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
  78. self.0.read(buf)
  79. }
  80. }
  81. /// Implement BufRead-Trait for Tuple-Struct R
  82. /// Simply calls `fill_buff` and `consume` from StdinLock
  83. impl<'a> BufRead for R<'a> {
  84. fn fill_buf(&mut self) -> Result<&[u8], io::Error> {
  85. self.0.fill_buf()
  86. }
  87. fn consume(&mut self, amt: usize) {
  88. self.0.consume(amt)
  89. }
  90. }
  91. /// Implement Write-Trait for Tuple-Struct W
  92. /// Simply calls `write` and `flush` from StdoutLock
  93. impl<'a> Write for W<'a> {
  94. fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
  95. self.0.write(buf)
  96. }
  97. fn flush(&mut self) -> Result<(), io::Error> {
  98. self.0.flush()
  99. }
  100. }