Skip to content

Commit fd70e93

Browse files
committed
take template as command, fetch pos
1 parent 222e603 commit fd70e93

2 files changed

Lines changed: 80 additions & 27 deletions

File tree

src/core_editor/line_buffer.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,15 @@ impl LineBuffer {
9090
self.lines[..self.insertion_point].matches('\n').count()
9191
}
9292

93+
/// Calculates the character index in the line the user is on
94+
///
95+
/// Zero-based index
96+
pub fn col(&self) -> usize {
97+
self.lines[self.line_start()..self.insertion_point]
98+
.chars()
99+
.count()
100+
}
101+
93102
/// Counts the number of lines in the buffer
94103
pub fn num_lines(&self) -> usize {
95104
self.lines.split('\n').count()

src/engine.rs

Lines changed: 71 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use std::path::PathBuf;
2-
31
use itertools::Itertools;
42
use nu_ansi_term::{Color, Style};
3+
use std::ffi::OsStr;
4+
use std::path::PathBuf;
55

66
use crate::{enums::ReedlineRawEvent, CursorConfig};
77
#[cfg(feature = "bashisms")]
@@ -47,6 +47,7 @@ use {
4747
terminal, QueueableCommand,
4848
},
4949
std::{
50+
ffi::OsString,
5051
fs::File,
5152
io,
5253
io::Result,
@@ -559,10 +560,6 @@ impl Reedline {
559560
/// ```
560561
#[must_use]
561562
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-
}
566563
self.buffer_editor = Some(BufferEditor {
567564
command: editor,
568565
temp_file,
@@ -1359,7 +1356,15 @@ impl Reedline {
13591356
}
13601357
Ok(EventStatus::Handled)
13611358
}
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+
}
13631368
ReedlineEvent::Resize(width, height) => {
13641369
self.last_render_snapshot = None;
13651370
self.painter.handle_resize(width, height);
@@ -1872,30 +1877,69 @@ impl Reedline {
18721877
}
18731878
}
18741879

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+
}
18891890

1890-
let res = std::fs::read_to_string(temp_file)?;
1891-
let res = res.trim_end().to_string();
1891+
command.spawn()?.wait()?;
18921892

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);
18941897

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);
18981940
}
1941+
1942+
cmd
18991943
}
19001944

19011945
/// Repaint logic for the history reverse search

0 commit comments

Comments
 (0)