|
1 | | -use std::path::PathBuf; |
2 | | - |
3 | 1 | use itertools::Itertools; |
4 | 2 | use nu_ansi_term::{Color, Style}; |
| 3 | +use std::ffi::OsStr; |
| 4 | +use std::path::PathBuf; |
5 | 5 |
|
6 | 6 | use crate::{enums::ReedlineRawEvent, CursorConfig}; |
7 | 7 | #[cfg(feature = "bashisms")] |
|
47 | 47 | terminal, QueueableCommand, |
48 | 48 | }, |
49 | 49 | std::{ |
| 50 | + ffi::OsString, |
50 | 51 | fs::File, |
51 | 52 | io, |
52 | 53 | io::Result, |
@@ -559,10 +560,6 @@ impl Reedline { |
559 | 560 | /// ``` |
560 | 561 | #[must_use] |
561 | 562 | pub fn with_buffer_editor(mut self, editor: Command, temp_file: PathBuf) -> Self { |
562 | | - let mut editor = editor; |
563 | | - if !editor.get_args().contains(&temp_file.as_os_str()) { |
564 | | - editor.arg(&temp_file); |
565 | | - } |
566 | 563 | self.buffer_editor = Some(BufferEditor { |
567 | 564 | command: editor, |
568 | 565 | temp_file, |
@@ -1359,7 +1356,15 @@ impl Reedline { |
1359 | 1356 | } |
1360 | 1357 | Ok(EventStatus::Handled) |
1361 | 1358 | } |
1362 | | - ReedlineEvent::OpenEditor => self.open_editor().map(|_| EventStatus::Handled), |
| 1359 | + ReedlineEvent::OpenEditor => { |
| 1360 | + if let Some(buffer_editor) = &self.buffer_editor { |
| 1361 | + let new_buffer = self.open_editor(buffer_editor)?; |
| 1362 | + self.editor |
| 1363 | + .set_buffer(new_buffer, UndoBehavior::CreateUndoPoint); |
| 1364 | + } |
| 1365 | + |
| 1366 | + Ok(EventStatus::Handled) |
| 1367 | + } |
1363 | 1368 | ReedlineEvent::Resize(width, height) => { |
1364 | 1369 | self.last_render_snapshot = None; |
1365 | 1370 | self.painter.handle_resize(width, height); |
@@ -1872,30 +1877,69 @@ impl Reedline { |
1872 | 1877 | } |
1873 | 1878 | } |
1874 | 1879 |
|
1875 | | - fn open_editor(&mut self) -> Result<()> { |
1876 | | - match &mut self.buffer_editor { |
1877 | | - Some(BufferEditor { |
1878 | | - ref mut command, |
1879 | | - ref temp_file, |
1880 | | - }) => { |
1881 | | - { |
1882 | | - let mut file = File::create(temp_file)?; |
1883 | | - write!(file, "{}", self.editor.get_buffer())?; |
1884 | | - } |
1885 | | - { |
1886 | | - let mut child = command.spawn()?; |
1887 | | - child.wait()?; |
1888 | | - } |
| 1880 | + /// opens the current buffer in the editor described in [`buffer_editor`] |
| 1881 | + /// returns the new buffer, after processing the changes via the editor |
| 1882 | + fn open_editor(&self, buffer_editor: &BufferEditor) -> Result<String> { |
| 1883 | + let mut command = Self::render_editor_command(buffer_editor, self.editor.line_buffer()); |
| 1884 | + |
| 1885 | + // flush buffer to temp file, so it can be read by the editor |
| 1886 | + { |
| 1887 | + let mut file = File::create(&buffer_editor.temp_file)?; |
| 1888 | + write!(file, "{}", self.editor.get_buffer())?; |
| 1889 | + } |
1889 | 1890 |
|
1890 | | - let res = std::fs::read_to_string(temp_file)?; |
1891 | | - let res = res.trim_end().to_string(); |
| 1891 | + command.spawn()?.wait()?; |
1892 | 1892 |
|
1893 | | - self.editor.set_buffer(res, UndoBehavior::CreateUndoPoint); |
| 1893 | + // fetch contents of buffer after editor is done |
| 1894 | + let mut buffer = std::fs::read_to_string(&buffer_editor.temp_file)?; |
| 1895 | + let content_len = buffer.trim_end().len(); |
| 1896 | + buffer.truncate(content_len); |
1894 | 1897 |
|
1895 | | - Ok(()) |
1896 | | - } |
1897 | | - _ => Ok(()), |
| 1898 | + Ok(buffer) |
| 1899 | + } |
| 1900 | + |
| 1901 | + /// renders the template command described in [`buffer_editor`], |
| 1902 | + /// by substituting the placeholders in the pattern, if any |
| 1903 | + fn render_editor_command(buffer_editor: &BufferEditor, line_buffer: &LineBuffer) -> Command { |
| 1904 | + use std::ops::Add as _; |
| 1905 | + |
| 1906 | + let mut cmd = Command::new(buffer_editor.command.get_program()); |
| 1907 | + |
| 1908 | + const FILE: &str = "{file}"; |
| 1909 | + const LINE: &str = "{line}"; |
| 1910 | + const COL: &str = "{col}"; |
| 1911 | + |
| 1912 | + // kind of a wonky check, but it's enough to know |
| 1913 | + // that we have somewhere to stick that temp_file path in |
| 1914 | + let is_template = buffer_editor |
| 1915 | + .command |
| 1916 | + .get_args() |
| 1917 | + .map(OsStr::to_string_lossy) |
| 1918 | + .any(|arg| arg.contains(FILE)); |
| 1919 | + |
| 1920 | + if is_template { |
| 1921 | + // TODO: there are more efficient ways to do this. |
| 1922 | + // e.g. "format args"-style structs |
| 1923 | + |
| 1924 | + let file = buffer_editor.temp_file.to_string_lossy(); |
| 1925 | + let line = line_buffer.line().add(1).to_string(); |
| 1926 | + let col = line_buffer.col().add(1).to_string(); |
| 1927 | + |
| 1928 | + let actual_args = buffer_editor |
| 1929 | + .command |
| 1930 | + .get_args() |
| 1931 | + .map(OsStr::to_string_lossy) |
| 1932 | + .map(|arg| arg.replace(FILE, &file)) |
| 1933 | + .map(|arg| arg.replace(LINE, &line)) |
| 1934 | + .map(|arg| arg.replace(COL, &col)); |
| 1935 | + |
| 1936 | + cmd.args(actual_args); |
| 1937 | + } else { |
| 1938 | + cmd.args(buffer_editor.command.get_args()); |
| 1939 | + cmd.arg(&buffer_editor.temp_file); |
1898 | 1940 | } |
| 1941 | + |
| 1942 | + cmd |
1899 | 1943 | } |
1900 | 1944 |
|
1901 | 1945 | /// Repaint logic for the history reverse search |
|
0 commit comments