/src/lib.rs

https://gitlab.com/cjcole/rust-linenoise · Rust · 202 lines · 124 code · 29 blank · 49 comment · 8 complexity · 4948e35814429cdbba0a415990d98017 MD5 · raw file

  1. #![crate_name="linenoise"]
  2. #![crate_type="lib"]
  3. //! This is a library that interfaces with the linenoise library.
  4. //! [Linenoise](https://github.com/antirez/linenoise) is a library implemented by Antirez, the Redis creator as a
  5. //! replacement for readline.
  6. //!
  7. //! This library is just a binding to this library.
  8. //!
  9. //! ```rust
  10. //! extern crate linenoise;
  11. //! fn callback(input: &str) -> Vec<String> {
  12. //! let mut ret : Vec<&str>;
  13. //! if input.starts_with("s") {
  14. //! ret = vec!["suggestion", "suggestion2", "suggestion-three"];
  15. //! } else {
  16. //! ret = vec!["wot"];
  17. //! }
  18. //!
  19. //! return ret.iter().map(|s| s.to_string()).collect();
  20. //! }
  21. //!
  22. //! fn main() {
  23. //! linenoise::set_callback(callback);
  24. //!
  25. //! loop {
  26. //! let val = linenoise::input("hello > ");
  27. //! match val {
  28. //! None => { break }
  29. //! Some(input) => {
  30. //! println!("> {}", input);
  31. //! linenoise::history_add(input.as_slice());
  32. //! if input.as_slice() == "clear" {
  33. //! linenoise::clear_screen();
  34. //! }
  35. //! }
  36. //! }
  37. //! }
  38. //! }
  39. //! ```
  40. extern crate libc;
  41. use std::ffi::CString;
  42. use std::ffi::CStr;
  43. use std::str;
  44. pub mod ffi;
  45. /// Sets the callback on interruption
  46. pub fn set_interrupt_callback(rust_cb: ffi::linenoiseInterruptCallback, ctx: *mut libc::c_void) {
  47. unsafe {
  48. ffi::linenoiseSetInterruptCallback(rust_cb, ctx);
  49. }
  50. }
  51. pub type Completions = ffi::Struct_linenoiseCompletions;
  52. type Callback = ffi::linenoiseCompletionCallback;
  53. pub type CompletionCallback = fn(&str) -> Vec<String>;
  54. static mut USER_COMPLETION: Option<CompletionCallback> = None;
  55. /// Sets the callback when tab is pressed
  56. pub fn set_callback(rust_cb: CompletionCallback ) {
  57. unsafe {
  58. USER_COMPLETION = Some(rust_cb);
  59. let ca = internal_callback as *mut _;
  60. ffi::linenoiseSetCompletionCallback(ca);
  61. }
  62. }
  63. /// Shows the prompt with your prompt as prefix
  64. /// Retuns the typed string or None is nothing or EOF
  65. pub fn input(prompt: &str) -> Option<String> {
  66. let cprompt = CString::new(prompt.as_bytes()).unwrap();
  67. unsafe {
  68. let cs = cprompt.as_ptr();
  69. let rret = ffi::linenoise(cs);
  70. let rval = if rret != 0 as *mut i8 {
  71. let ptr = rret as *const i8;
  72. let cast = str::from_utf8(CStr::from_ptr(ptr).to_bytes()).unwrap().to_string();
  73. libc::free(ptr as *mut libc::c_void);
  74. Some(cast)
  75. } else {
  76. None
  77. };
  78. return rval;
  79. }
  80. }
  81. /// Add this string to the history
  82. pub fn history_add(line: &str) -> i32 {
  83. let cs = CString::new(line).unwrap().as_ptr();
  84. let ret: i32;
  85. unsafe {
  86. ret = ffi::linenoiseHistoryAdd(cs);
  87. }
  88. ret
  89. }
  90. /// Set max length history
  91. pub fn history_set_max_len(len: i32) -> i32 {
  92. let ret: i32;
  93. unsafe {
  94. ret = ffi::linenoiseHistorySetMaxLen(len);
  95. }
  96. ret
  97. }
  98. /// Save the history on disk
  99. pub fn history_save(file: &str) -> i32 {
  100. let fname = CString::new(file).unwrap().as_ptr();
  101. let ret: i32;
  102. unsafe {
  103. ret = ffi::linenoiseHistorySave(fname);
  104. }
  105. ret
  106. }
  107. /// Load the history on disk
  108. pub fn history_load(file: &str) -> i32 {
  109. let fname = CString::new(file).unwrap().as_ptr();
  110. let ret: i32;
  111. unsafe {
  112. ret = ffi::linenoiseHistoryLoad(fname);
  113. }
  114. ret
  115. }
  116. /// Get a line from the history by (zero-based) index
  117. pub fn history_line(index: i32) -> Option<String> {
  118. unsafe {
  119. let ret = ffi::linenoiseHistoryLine(index);
  120. let rval = if ret != 0 as *mut i8 {
  121. let ptr = ret as *const i8;
  122. let cast = str::from_utf8(CStr::from_ptr(ptr).to_bytes()).unwrap().to_string();
  123. libc::free(ptr as *mut libc::c_void);
  124. Some(cast)
  125. } else {
  126. None
  127. };
  128. return rval;
  129. }
  130. }
  131. ///Clears the screen
  132. pub fn clear_screen() {
  133. unsafe {
  134. ffi::linenoiseClearScreen();
  135. }
  136. }
  137. pub fn set_multiline(ml: i32) {
  138. unsafe {
  139. ffi::linenoiseSetMultiLine(ml);
  140. }
  141. }
  142. pub fn print_key_codes() {
  143. unsafe {
  144. ffi::linenoisePrintKeyCodes();
  145. }
  146. }
  147. /// Add a completion to the current list of completions.
  148. pub fn add_completion(c: *mut Completions, s: &str) {
  149. unsafe {
  150. ffi::linenoiseAddCompletion(c, CString::new(s).unwrap().as_ptr());
  151. }
  152. }
  153. fn internal_callback(cs: *mut libc::c_char, lc:*mut Completions ) {
  154. unsafe {
  155. (*lc).len = 0;
  156. }
  157. let cr = cs as *const _;
  158. unsafe {
  159. let input = str::from_utf8(CStr::from_ptr(cr).to_bytes()).unwrap();
  160. for external_callback in USER_COMPLETION.iter() {
  161. let ret = (*external_callback)(input);
  162. for x in ret.iter() {
  163. add_completion(lc, x.as_ref());
  164. }
  165. }
  166. }
  167. }
  168. /// Interrupts input
  169. pub fn interrupt() {
  170. unsafe {
  171. ffi::linenoiseInterrupt();
  172. }
  173. }