1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
//! Add-Ed is a library implementing the parsing and runtime for Ed in rust. //! //! It exports two traits, Buffer and UI, which define the exchangeable parts of the editor. //! //! An implementation of the UI trait is needed to support the 'g' command and similar, DummyUI. //! It is used for macro execution, by taking prepared input from a input list rather than prompting the user. //! //! Since the buffer is rather complex a standard Buffer implementation can be build in with the feature "vecbuffer". //! It is recommended to compare the behaviour of any Buffer implementation to the VecBuffer until Buffer tests are set up. //! //! An example of how to use this library is in src/bin/classic.rs pub mod error_consts; mod cmd; pub mod ui; pub mod buffer; use ui::UI; use buffer::Buffer; /// The state variable used by the editor to track its internal state pub struct Ed <'a, B: Buffer> { // Track the currently selected lines in the buffer // This is usually separate from viewed lines in the UI selection: Option<(usize, usize)>, // A mutable reference to a Buffer implementor // The buffer implementor will handle most of the operations and store the data buffer: &'a mut B, // The path to the currently selected file path: String, // The previous search_replace's arguments, to support repeating the last s_args: Option<(String, String, bool)>, // Wether or not to print errors when they occur (if not, print ? instead of error) print_errors: bool, // The previous error that occured, since we may not have printed it error: Option<&'static str>, } impl <'a, B: Buffer> Ed <'a, B> { /// Construct a new instance of Ed /// /// * An empty file string is recommended if no filepath is opened /// * Note that you can initialise the buffer with contents before this pub fn new( buffer: &'a mut B, path: String, ) -> Result<Self, &'static str> { let len = path.len(); if len != 0 { buffer.read_from(&path, None, false)?; } let tmp = Self { // Sane defaults for initial settings print_errors: true, error: None, s_args: None, // Trying to set a reasonable default tends to cause trouble selection: None, // And the given values buffer: buffer, path: path, }; Ok(tmp) } /// Run the given command /// /// Returns true if the command was to quit pub fn run_command( &mut self, ui: &mut dyn UI, command: &str, ) -> Result<bool, &'static str> { // Just hand execution into the cmd module match cmd::run(self, ui, command) { // If error, note it in state Err(e) => { self.error = Some(e); Err(e) }, x => x, } } /// Run given instance of Ed until it receives a command to quit or errors /// /// The returned error type could be improved, suggestions welcome. pub fn run_macro( &mut self, ui: &mut dyn UI, ) -> Result<(), &'static str> { // Loop until quit or error loop { let cmd = match ui.get_command( self.buffer ) { Err(e) => { self.error = Some(e); return Err(e) }, Ok(x) => x, }; if self.run_command(ui, &cmd)? { break; } } Ok(()) } pub fn run( &mut self, ui: &mut dyn UI, ) -> Result<(), &'static str> { loop { match self.run_macro(ui) { Ok(()) => break, Err(_) => { if self.print_errors { ui.print(self.error.unwrap())?; } else { ui.print("?\n")?; } }, } } Ok(()) } }