on master help sign in
document should save even if formatter fails
3f07885Skyler Hawthorne
helix-core/src/syntax.rs+6
@@ -61,6 +61,12 @@ pub struct Configuration {
61 pub language: Vec<LanguageConfiguration>,
61 pub language: Vec<LanguageConfiguration>,
62}
62}
63
63
64+impl Default for Configuration {
65+ fn default() -> Self {
66+ crate::config::default_syntax_loader()
67+ }
68+}
69+
64// largely based on tree-sitter/cli/src/loader.rs
70// largely based on tree-sitter/cli/src/loader.rs
65#[derive(Debug, Serialize, Deserialize)]
71#[derive(Debug, Serialize, Deserialize)]
66#[serde(rename_all = "kebab-case", deny_unknown_fields)]
72#[serde(rename_all = "kebab-case", deny_unknown_fields)]
helix-term/src/application.rs+5−10
@@ -1,7 +1,6 @@
1use arc_swap::{access::Map, ArcSwap};
1use arc_swap::{access::Map, ArcSwap};
2use futures_util::Stream;
2use futures_util::Stream;
3use helix_core::{
3use helix_core::{
4− config::{default_syntax_loader, user_syntax_loader},
5 diagnostic::{DiagnosticTag, NumberOrString},
4 diagnostic::{DiagnosticTag, NumberOrString},
6 path::get_relative_path,
5 path::get_relative_path,
7 pos_at_coords, syntax, Selection,
6 pos_at_coords, syntax, Selection,
@@ -110,7 +109,11 @@ fn restore_term() -> Result<(), Error> {
110}
109}
111
110
112impl Application {
111impl Application {
112+ pub fn new(
113+ args: Args,
114+ config: Config,
115+ syn_loader_conf: syntax::Configuration,
113− pub fn new(args: Args, config: Config) -> Result<Self, Error> {
116+ ) -> Result<Self, Error> {
114 #[cfg(feature = "integration")]
117 #[cfg(feature = "integration")]
115 setup_integration_logging();
118 setup_integration_logging();
116
119
@@ -137,14 +140,6 @@ impl Application {
137 })
140 })
138 .unwrap_or_else(|| theme_loader.default_theme(true_color));
141 .unwrap_or_else(|| theme_loader.default_theme(true_color));
139
142
140− let syn_loader_conf = user_syntax_loader().unwrap_or_else(|err| {
141− eprintln!("Bad language config: {}", err);
142− eprintln!("Press <ENTER> to continue with default language config");
143− use std::io::Read;
144− // This waits for an enter press.
145− let _ = std::io::stdin().read(&mut []);
146− default_syntax_loader()
147− });
148 let syn_loader = std::sync::Arc::new(syntax::Loader::new(syn_loader_conf));
143 let syn_loader = std::sync::Arc::new(syntax::Loader::new(syn_loader_conf));
149
144
150 let mut compositor = Compositor::new().context("build compositor")?;
145 let mut compositor = Compositor::new().context("build compositor")?;
helix-term/src/commands.rs+15−12
@@ -2518,7 +2518,8 @@ async fn make_format_callback(
2518 format: impl Future<Output = Result<Transaction, FormatterError>> + Send + 'static,
2518 format: impl Future<Output = Result<Transaction, FormatterError>> + Send + 'static,
2519 write: Option<(Option<PathBuf>, bool)>,
2519 write: Option<(Option<PathBuf>, bool)>,
2520) -> anyhow::Result<job::Callback> {
2520) -> anyhow::Result<job::Callback> {
2521− let format = format.await?;
2521+ let format = format.await;
2522+
2522 let call: job::Callback = Callback::Editor(Box::new(move |editor| {
2523 let call: job::Callback = Callback::Editor(Box::new(move |editor| {
2523 if !editor.documents.contains_key(&doc_id) {
2524 if !editor.documents.contains_key(&doc_id) {
2524 return;
2525 return;
@@ -2528,19 +2529,21 @@ async fn make_format_callback(
2528 let doc = doc_mut!(editor, &doc_id);
2529 let doc = doc_mut!(editor, &doc_id);
2529 let view = view_mut!(editor);
2530 let view = view_mut!(editor);
2530
2531
2532+ if let Ok(format) = format {
2531− if doc.version() == doc_version {
2533+ if doc.version() == doc_version {
2532− apply_transaction(&format, doc, view);
2534+ apply_transaction(&format, doc, view);
2533− doc.append_changes_to_history(view.id);
2535+ doc.append_changes_to_history(view.id);
2534− doc.detect_indent_and_line_ending();
2536+ doc.detect_indent_and_line_ending();
2535− view.ensure_cursor_in_view(doc, scrolloff);
2537+ view.ensure_cursor_in_view(doc, scrolloff);
2538+ } else {
2539+ log::info!("discarded formatting changes because the document changed");
2540+ }
2541+ }
2536
2542
2537− if let Some((path, force)) = write {
2543+ if let Some((path, force)) = write {
2538− if let Err(err) = doc.save(path, force) {
2544+ if let Err(err) = doc.save(path, force) {
2539− editor.set_error(format!("Error saving: {}", err));
2545+ editor.set_error(format!("Error saving: {}", err));
2540− }
2541 }
2546 }
2542− } else {
2543− log::info!("discarded formatting changes because the document changed");
2544 }
2547 }
2545 }));
2548 }));
2546
2549
helix-term/src/main.rs+11−1
@@ -139,8 +139,18 @@ FLAGS:
139 Err(err) => return Err(Error::new(err)),
139 Err(err) => return Err(Error::new(err)),
140 };
140 };
141
141
142+ let syn_loader_conf = helix_core::config::user_syntax_loader().unwrap_or_else(|err| {
143+ eprintln!("Bad language config: {}", err);
144+ eprintln!("Press <ENTER> to continue with default language config");
145+ use std::io::Read;
146+ // This waits for an enter press.
147+ let _ = std::io::stdin().read(&mut []);
148+ helix_core::config::default_syntax_loader()
149+ });
150+
142 // TODO: use the thread local executor to spawn the application task separately from the work pool
151 // TODO: use the thread local executor to spawn the application task separately from the work pool
152+ let mut app = Application::new(args, config, syn_loader_conf)
143− let mut app = Application::new(args, config).context("unable to create new application")?;
153+ .context("unable to create new application")?;
144
154
145 let exit_code = app.run(&mut EventStream::new()).await?;
155 let exit_code = app.run(&mut EventStream::new()).await?;
146
156
helix-term/tests/test/auto_indent.rs+1
@@ -8,6 +8,7 @@ async fn auto_indent_c() -> anyhow::Result<()> {
8 ..Default::default()
8 ..Default::default()
9 },
9 },
10 Config::default(),
10 Config::default(),
11+ helpers::test_syntax_conf(None),
11 // switches to append mode?
12 // switches to append mode?
12 (
13 (
13 helpers::platform_line("void foo() {#[|}]#").as_ref(),
14 helpers::platform_line("void foo() {#[|}]#").as_ref(),
helix-term/tests/test/auto_pairs.rs+1
@@ -13,6 +13,7 @@ async fn auto_pairs_basic() -> anyhow::Result<()> {
13 },
13 },
14 ..Default::default()
14 ..Default::default()
15 },
15 },
16+ helpers::test_syntax_conf(None),
16 ("#[\n|]#", "i(<esc>", "(#[|\n]#"),
17 ("#[\n|]#", "i(<esc>", "(#[|\n]#"),
17 )
18 )
18 .await?;
19 .await?;
helix-term/tests/test/commands.rs+10−4
@@ -1,16 +1,18 @@
1use std::ops::RangeInclusive;
1use std::ops::RangeInclusive;
2
2
3use helix_core::diagnostic::Severity;
3use helix_core::diagnostic::Severity;
4−use helix_term::application::Application;
5
4
6use super::*;
5use super::*;
7
6
8#[tokio::test(flavor = "multi_thread")]
7#[tokio::test(flavor = "multi_thread")]
9async fn test_write_quit_fail() -> anyhow::Result<()> {
8async fn test_write_quit_fail() -> anyhow::Result<()> {
10 let file = helpers::new_readonly_tempfile()?;
9 let file = helpers::new_readonly_tempfile()?;
10+ let mut app = helpers::AppBuilder::new()
11+ .with_file(file.path(), None)
12+ .build()?;
11
13
12 test_key_sequence(
14 test_key_sequence(
13− &mut helpers::app_with_file(file.path())?,
15+ &mut app,
14 Some("ihello<esc>:wq<ret>"),
16 Some("ihello<esc>:wq<ret>"),
15 Some(&|app| {
17 Some(&|app| {
16 let mut docs: Vec<_> = app.editor.documents().collect();
18 let mut docs: Vec<_> = app.editor.documents().collect();
@@ -30,7 +32,7 @@ async fn test_write_quit_fail() -> anyhow::Result<()> {
30#[tokio::test(flavor = "multi_thread")]
32#[tokio::test(flavor = "multi_thread")]
31async fn test_buffer_close_concurrent() -> anyhow::Result<()> {
33async fn test_buffer_close_concurrent() -> anyhow::Result<()> {
32 test_key_sequences(
34 test_key_sequences(
33− &mut Application::new(Args::default(), Config::default())?,
35+ &mut helpers::AppBuilder::new().build()?,
34 vec![
36 vec![
35 (
37 (
36 None,
38 None,
@@ -70,8 +72,12 @@ async fn test_buffer_close_concurrent() -> anyhow::Result<()> {
70
72
71 command.push_str(":buffer<minus>close<ret>");
73 command.push_str(":buffer<minus>close<ret>");
72
74
75+ let mut app = helpers::AppBuilder::new()
76+ .with_file(file.path(), None)
77+ .build()?;
78+
73 test_key_sequence(
79 test_key_sequence(
74− &mut helpers::app_with_file(file.path())?,
80+ &mut app,
75 Some(&command),
81 Some(&command),
76 Some(&|app| {
82 Some(&|app| {
77 assert!(!app.editor.is_err(), "error: {:?}", app.editor.get_status());
83 assert!(!app.editor.is_err(), "error: {:?}", app.editor.get_status());
helix-term/tests/test/helpers.rs+77−13
@@ -108,7 +108,7 @@ pub async fn test_key_sequence_with_input_text<T: Into<TestCase>>(
108 let test_case = test_case.into();
108 let test_case = test_case.into();
109 let mut app = match app {
109 let mut app = match app {
110 Some(app) => app,
110 Some(app) => app,
111− None => Application::new(Args::default(), Config::default())?,
111+ None => Application::new(Args::default(), Config::default(), test_syntax_conf(None))?,
112 };
112 };
113
113
114 let (view, doc) = helix_view::current!(app.editor);
114 let (view, doc) = helix_view::current!(app.editor);
@@ -132,16 +132,30 @@ pub async fn test_key_sequence_with_input_text<T: Into<TestCase>>(
132 .await
132 .await
133}
133}
134
134
135+/// Generates language configs that merge in overrides, like a user language
136+/// config. The argument string must be a raw TOML document.
137+pub fn test_syntax_conf(overrides: Option<String>) -> helix_core::syntax::Configuration {
138+ let mut lang = helix_loader::config::default_lang_config();
139+
140+ if let Some(overrides) = overrides {
141+ let override_toml = toml::from_str(&overrides).unwrap();
142+ lang = helix_loader::merge_toml_values(lang, override_toml, 3);
143+ }
144+
145+ lang.try_into().unwrap()
146+}
147+
135/// Use this for very simple test cases where there is one input
148/// Use this for very simple test cases where there is one input
136/// document, selection, and sequence of key presses, and you just
149/// document, selection, and sequence of key presses, and you just
137/// want to verify the resulting document and selection.
150/// want to verify the resulting document and selection.
138pub async fn test_with_config<T: Into<TestCase>>(
151pub async fn test_with_config<T: Into<TestCase>>(
139 args: Args,
152 args: Args,
140 config: Config,
153 config: Config,
154+ syn_conf: helix_core::syntax::Configuration,
141 test_case: T,
155 test_case: T,
142) -> anyhow::Result<()> {
156) -> anyhow::Result<()> {
143 let test_case = test_case.into();
157 let test_case = test_case.into();
144− let app = Application::new(args, config)?;
158+ let app = Application::new(args, config, syn_conf)?;
145
159
146 test_key_sequence_with_input_text(
160 test_key_sequence_with_input_text(
147 Some(app),
161 Some(app),
@@ -162,7 +176,13 @@ pub async fn test_with_config<T: Into<TestCase>>(
162}
176}
163
177
164pub async fn test<T: Into<TestCase>>(test_case: T) -> anyhow::Result<()> {
178pub async fn test<T: Into<TestCase>>(test_case: T) -> anyhow::Result<()> {
165− test_with_config(Args::default(), Config::default(), test_case).await
179+ test_with_config(
180+ Args::default(),
181+ Config::default(),
182+ test_syntax_conf(None),
183+ test_case,
184+ )
185+ .await
166}
186}
167
187
168pub fn temp_file_with_contents<S: AsRef<str>>(
188pub fn temp_file_with_contents<S: AsRef<str>>(
@@ -207,16 +227,60 @@ pub fn new_readonly_tempfile() -> anyhow::Result<NamedTempFile> {
207 Ok(file)
227 Ok(file)
208}
228}
209
229
210−/// Creates a new Application with default config that opens the given file
230+#[derive(Default)]
211−/// path
231+pub struct AppBuilder {
232+ args: Args,
233+ config: Config,
234+ syn_conf: helix_core::syntax::Configuration,
235+ input: Option<(String, Selection)>,
236+}
237+
238+impl AppBuilder {
239+ pub fn new() -> Self {
240+ AppBuilder::default()
241+ }
242+
243+ pub fn with_file<P: Into<PathBuf>>(
244+ mut self,
245+ path: P,
246+ pos: Option<helix_core::Position>,
247+ ) -> Self {
248+ self.args.files.push((path.into(), pos.unwrap_or_default()));
249+ self
250+ }
251+
252+ pub fn with_config(mut self, config: Config) -> Self {
253+ self.config = config;
254+ self
255+ }
256+
257+ pub fn with_input_text<S: Into<String>>(mut self, input_text: S) -> Self {
258+ self.input = Some(test::print(&input_text.into()));
259+ self
260+ }
261+
262+ pub fn with_lang_config(mut self, syn_conf: helix_core::syntax::Configuration) -> Self {
263+ self.syn_conf = syn_conf;
264+ self
265+ }
266+
212−pub fn app_with_file<P: Into<PathBuf>>(path: P) -> anyhow::Result<Application> {
267+ pub fn build(self) -> anyhow::Result<Application> {
213− Application::new(
268+ let mut app = Application::new(self.args, self.config, self.syn_conf)?;
214− Args {
269+
215− files: vec![(path.into(), helix_core::Position::default())],
270+ if let Some((text, selection)) = self.input {
216− ..Default::default()
271+ let (view, doc) = helix_view::current!(app.editor);
272+ let sel = doc.selection(view.id).clone();
273+ let trans = Transaction::change_by_selection(doc.text(), &sel, |_| {
274+ (0, doc.text().len_chars(), Some((text.clone()).into()))
275+ })
276+ .with_selection(selection);
277+
278+ // replace the initial text with the input text
279+ doc.apply(&trans, view.id);
217− },
280+ }
218− Config::default(),
281+
219− )
282+ Ok(app)
283+ }
220}
284}
221
285
222pub fn assert_file_has_content(file: &mut File, content: &str) -> anyhow::Result<()> {
286pub fn assert_file_has_content(file: &mut File, content: &str) -> anyhow::Result<()> {
helix-term/tests/test/movement.rs+3−1
@@ -70,7 +70,9 @@ async fn insert_to_normal_mode_cursor_position() -> anyhow::Result<()> {
70async fn cursor_position_newly_opened_file() -> anyhow::Result<()> {
70async fn cursor_position_newly_opened_file() -> anyhow::Result<()> {
71 let test = |content: &str, expected_sel: Selection| -> anyhow::Result<()> {
71 let test = |content: &str, expected_sel: Selection| -> anyhow::Result<()> {
72 let file = helpers::temp_file_with_contents(content)?;
72 let file = helpers::temp_file_with_contents(content)?;
73− let mut app = helpers::app_with_file(file.path())?;
73+ let mut app = helpers::AppBuilder::new()
74+ .with_file(file.path(), None)
75+ .build()?;
74
76
75 let (view, doc) = helix_view::current!(app.editor);
77 let (view, doc) = helix_view::current!(app.editor);
76 let sel = doc.selection(view.id).clone();
78 let sel = doc.selection(view.id).clone();
helix-term/tests/test/prompt.rs+1−3
@@ -1,11 +1,9 @@
1use super::*;
1use super::*;
2
2
3−use helix_term::application::Application;
4−
5#[tokio::test]
3#[tokio::test]
6async fn test_history_completion() -> anyhow::Result<()> {
4async fn test_history_completion() -> anyhow::Result<()> {
7 test_key_sequence(
5 test_key_sequence(
8− &mut Application::new(Args::default(), Config::default())?,
6+ &mut AppBuilder::new().build()?,
9 Some(":asdf<ret>:theme d<C-n><tab>"),
7 Some(":asdf<ret>:theme d<C-n><tab>"),
10 Some(&|app| {
8 Some(&|app| {
11 assert!(!app.editor.is_err());
9 assert!(!app.editor.is_err());
helix-term/tests/test/splits.rs+9−2
@@ -6,8 +6,12 @@ async fn test_split_write_quit_all() -> anyhow::Result<()> {
6 let mut file2 = tempfile::NamedTempFile::new()?;
6 let mut file2 = tempfile::NamedTempFile::new()?;
7 let mut file3 = tempfile::NamedTempFile::new()?;
7 let mut file3 = tempfile::NamedTempFile::new()?;
8
8
9+ let mut app = helpers::AppBuilder::new()
10+ .with_file(file1.path(), None)
11+ .build()?;
12+
9 test_key_sequences(
13 test_key_sequences(
10− &mut helpers::app_with_file(file1.path())?,
14+ &mut app,
11 vec![
15 vec![
12 (
16 (
13 Some(&format!(
17 Some(&format!(
@@ -66,9 +70,12 @@ async fn test_split_write_quit_all() -> anyhow::Result<()> {
66#[tokio::test(flavor = "multi_thread")]
70#[tokio::test(flavor = "multi_thread")]
67async fn test_split_write_quit_same_file() -> anyhow::Result<()> {
71async fn test_split_write_quit_same_file() -> anyhow::Result<()> {
68 let mut file = tempfile::NamedTempFile::new()?;
72 let mut file = tempfile::NamedTempFile::new()?;
73+ let mut app = helpers::AppBuilder::new()
74+ .with_file(file.path(), None)
75+ .build()?;
69
76
70 test_key_sequences(
77 test_key_sequences(
71− &mut helpers::app_with_file(file.path())?,
78+ &mut app,
72 vec![
79 vec![
73 (
80 (
74 Some("O<esc>ihello<esc>:sp<ret>ogoodbye<esc>"),
81 Some("O<esc>ihello<esc>:sp<ret>ogoodbye<esc>"),
helix-term/tests/test/write.rs+46−20
@@ -4,7 +4,6 @@ use std::{
4};
4};
5
5
6use helix_core::diagnostic::Severity;
6use helix_core::diagnostic::Severity;
7−use helix_term::application::Application;
8use helix_view::doc;
7use helix_view::doc;
9
8
10use super::*;
9use super::*;
@@ -12,9 +11,12 @@ use super::*;
12#[tokio::test]
11#[tokio::test]
13async fn test_write() -> anyhow::Result<()> {
12async fn test_write() -> anyhow::Result<()> {
14 let mut file = tempfile::NamedTempFile::new()?;
13 let mut file = tempfile::NamedTempFile::new()?;
14+ let mut app = helpers::AppBuilder::new()
15+ .with_file(file.path(), None)
16+ .build()?;
15
17
16 test_key_sequence(
18 test_key_sequence(
17− &mut helpers::app_with_file(file.path())?,
19+ &mut app,
18 Some("ithe gostak distims the doshes<ret><esc>:w<ret>"),
20 Some("ithe gostak distims the doshes<ret><esc>:w<ret>"),
19 None,
21 None,
20 false,
22 false,
@@ -38,9 +40,12 @@ async fn test_write() -> anyhow::Result<()> {
38#[tokio::test(flavor = "multi_thread")]
40#[tokio::test(flavor = "multi_thread")]
39async fn test_write_quit() -> anyhow::Result<()> {
41async fn test_write_quit() -> anyhow::Result<()> {
40 let mut file = tempfile::NamedTempFile::new()?;
42 let mut file = tempfile::NamedTempFile::new()?;
43+ let mut app = helpers::AppBuilder::new()
44+ .with_file(file.path(), None)
45+ .build()?;
41
46
42 test_key_sequence(
47 test_key_sequence(
43− &mut helpers::app_with_file(file.path())?,
48+ &mut app,
44 Some("ithe gostak distims the doshes<ret><esc>:wq<ret>"),
49 Some("ithe gostak distims the doshes<ret><esc>:wq<ret>"),
45 None,
50 None,
46 true,
51 true,
@@ -66,19 +71,16 @@ async fn test_write_concurrent() -> anyhow::Result<()> {
66 let mut file = tempfile::NamedTempFile::new()?;
71 let mut file = tempfile::NamedTempFile::new()?;
67 let mut command = String::new();
72 let mut command = String::new();
68 const RANGE: RangeInclusive<i32> = 1..=5000;
73 const RANGE: RangeInclusive<i32> = 1..=5000;
74+ let mut app = helpers::AppBuilder::new()
75+ .with_file(file.path(), None)
76+ .build()?;
69
77
70 for i in RANGE {
78 for i in RANGE {
71 let cmd = format!("%c{}<esc>:w<ret>", i);
79 let cmd = format!("%c{}<esc>:w<ret>", i);
72 command.push_str(&cmd);
80 command.push_str(&cmd);
73 }
81 }
74
82
75− test_key_sequence(
83+ test_key_sequence(&mut app, Some(&command), None, false).await?;
76− &mut helpers::app_with_file(file.path())?,
77− Some(&command),
78− None,
79− false,
80− )
81− .await?;
82
84
83 file.as_file_mut().flush()?;
85 file.as_file_mut().flush()?;
84 file.as_file_mut().sync_all()?;
86 file.as_file_mut().sync_all()?;
@@ -93,9 +95,12 @@ async fn test_write_concurrent() -> anyhow::Result<()> {
93#[tokio::test]
95#[tokio::test]
94async fn test_write_fail_mod_flag() -> anyhow::Result<()> {
96async fn test_write_fail_mod_flag() -> anyhow::Result<()> {
95 let file = helpers::new_readonly_tempfile()?;
97 let file = helpers::new_readonly_tempfile()?;
98+ let mut app = helpers::AppBuilder::new()
99+ .with_file(file.path(), None)
100+ .build()?;
96
101
97 test_key_sequences(
102 test_key_sequences(
98− &mut helpers::app_with_file(file.path())?,
103+ &mut app,
99 vec![
104 vec![
100 (
105 (
101 None,
106 None,
@@ -133,7 +138,7 @@ async fn test_write_scratch_to_new_path() -> anyhow::Result<()> {
133 let mut file = tempfile::NamedTempFile::new()?;
138 let mut file = tempfile::NamedTempFile::new()?;
134
139
135 test_key_sequence(
140 test_key_sequence(
136− &mut Application::new(Args::default(), Config::default())?,
141+ &mut AppBuilder::new().build()?,
137 Some(format!("ihello<esc>:w {}<ret>", file.path().to_string_lossy()).as_ref()),
142 Some(format!("ihello<esc>:w {}<ret>", file.path().to_string_lossy()).as_ref()),
138 Some(&|app| {
143 Some(&|app| {
139 assert!(!app.editor.is_err());
144 assert!(!app.editor.is_err());
@@ -174,19 +179,40 @@ async fn test_write_scratch_no_path_fails() -> anyhow::Result<()> {
174 Ok(())
179 Ok(())
175}
180}
176
181
182+#[tokio::test]
183+async fn test_write_auto_format_fails_still_writes() -> anyhow::Result<()> {
184+ let mut file = tempfile::Builder::new().suffix(".rs").tempfile()?;
185+
186+ let lang_conf = indoc! {r#"
187+ [[language]]
188+ name = "rust"
189+ formatter = { command = "bash", args = [ "-c", "exit 1" ] }
190+ "#};
191+
192+ let mut app = helpers::AppBuilder::new()
193+ .with_file(file.path(), None)
194+ .with_input_text("#[l|]#et foo = 0;\n")
195+ .with_lang_config(helpers::test_syntax_conf(Some(lang_conf.into())))
196+ .build()?;
197+
198+ test_key_sequences(&mut app, vec![(Some(":w<ret>"), None)], false).await?;
199+
200+ // file still saves
201+ helpers::assert_file_has_content(file.as_file_mut(), "let foo = 0;\n")?;
202+
203+ Ok(())
204+}
205+
177#[tokio::test]
206#[tokio::test]
178async fn test_write_new_path() -> anyhow::Result<()> {
207async fn test_write_new_path() -> anyhow::Result<()> {
179 let mut file1 = tempfile::NamedTempFile::new().unwrap();
208 let mut file1 = tempfile::NamedTempFile::new().unwrap();
180 let mut file2 = tempfile::NamedTempFile::new().unwrap();
209 let mut file2 = tempfile::NamedTempFile::new().unwrap();
210+ let mut app = helpers::AppBuilder::new()
211+ .with_file(file1.path(), None)
212+ .build()?;
181
213
182 test_key_sequences(
214 test_key_sequences(
183− &mut Application::new(
215+ &mut app,
184− Args {
185− files: vec![(file1.path().to_path_buf(), Position::default())],
186− ..Default::default()
187− },
188− Config::default(),
189− )?,
190 vec![
216 vec![
191 (
217 (
192 Some("ii can eat glass, it will not hurt me<ret><esc>:w<ret>"),
218 Some("ii can eat glass, it will not hurt me<ret><esc>:w<ret>"),
@@ -228,7 +254,7 @@ async fn test_write_fail_new_path() -> anyhow::Result<()> {
228 let file = helpers::new_readonly_tempfile()?;
254 let file = helpers::new_readonly_tempfile()?;
229
255
230 test_key_sequences(
256 test_key_sequences(
231− &mut Application::new(Args::default(), Config::default())?,
257+ &mut AppBuilder::new().build()?,
232 vec![
258 vec![
233 (
259 (
234 None,
260 None,