@@ -1,9 +1,8 @@
+use super::*;
use crate::test::{
assert_text_with_selections, build_editor, select_ranges, EditorLspTestContext,
EditorTestContext,
};
-
-use super::*;
use futures::StreamExt;
use gpui::{
geometry::rect::RectF,
@@ -418,12 +417,12 @@ fn test_canceling_pending_selection(cx: &mut gpui::MutableAppContext) {
fn test_clone(cx: &mut gpui::MutableAppContext) {
let (text, selection_ranges) = marked_text_ranges(
indoc! {"
- one
- two
- threeˇ
- four
- fiveˇ
- "},
+ one
+ two
+ threeˇ
+ four
+ fiveˇ
+ "},
true,
);
cx.set_global(Settings::test(cx));
@@ -624,22 +623,22 @@ fn test_fold(cx: &mut gpui::MutableAppContext) {
cx.set_global(Settings::test(cx));
let buffer = MultiBuffer::build_simple(
&"
- impl Foo {
- // Hello!
+ impl Foo {
+ // Hello!
- fn a() {
- 1
- }
+ fn a() {
+ 1
+ }
- fn b() {
- 2
- }
+ fn b() {
+ 2
+ }
- fn c() {
- 3
- }
+ fn c() {
+ 3
}
- "
+ }
+ "
.unindent(),
cx,
);
@@ -653,20 +652,20 @@ fn test_fold(cx: &mut gpui::MutableAppContext) {
assert_eq!(
view.display_text(cx),
"
- impl Foo {
- // Hello!
+ impl Foo {
+ // Hello!
- fn a() {
- 1
- }
+ fn a() {
+ 1
+ }
- fn b() {…
- }
+ fn b() {…
+ }
- fn c() {…
- }
+ fn c() {…
}
- "
+ }
+ "
.unindent(),
);
@@ -674,9 +673,9 @@ fn test_fold(cx: &mut gpui::MutableAppContext) {
assert_eq!(
view.display_text(cx),
"
- impl Foo {…
- }
- "
+ impl Foo {…
+ }
+ "
.unindent(),
);
@@ -684,20 +683,20 @@ fn test_fold(cx: &mut gpui::MutableAppContext) {
assert_eq!(
view.display_text(cx),
"
- impl Foo {
- // Hello!
+ impl Foo {
+ // Hello!
- fn a() {
- 1
- }
+ fn a() {
+ 1
+ }
- fn b() {…
- }
+ fn b() {…
+ }
- fn c() {…
- }
+ fn c() {…
}
- "
+ }
+ "
.unindent(),
);
@@ -1264,14 +1263,14 @@ fn test_newline_with_old_selections(cx: &mut gpui::MutableAppContext) {
cx.set_global(Settings::test(cx));
let buffer = MultiBuffer::build_simple(
"
- a
- b(
- X
- )
- c(
- X
- )
- "
+ a
+ b(
+ X
+ )
+ c(
+ X
+ )
+ "
.unindent()
.as_str(),
cx,
@@ -1301,10 +1300,10 @@ fn test_newline_with_old_selections(cx: &mut gpui::MutableAppContext) {
assert_eq!(
buffer.read(cx).text(),
"
- a
- b()
- c()
- "
+ a
+ b()
+ c()
+ "
.unindent()
);
});
@@ -1322,12 +1321,12 @@ fn test_newline_with_old_selections(cx: &mut gpui::MutableAppContext) {
assert_eq!(
editor.text(cx),
"
- a
- b(
- )
- c(
- )
- "
+ a
+ b(
+ )
+ c(
+ )
+ "
.unindent()
);
@@ -1362,33 +1361,33 @@ async fn test_newline_below(cx: &mut gpui::TestAppContext) {
cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx));
cx.set_state(indoc! {"
- const a: ˇA = (
- (ˇ
- «const_functionˇ»(ˇ),
- so«mˇ»et«hˇ»ing_ˇelse,ˇ
- )ˇ
- ˇ);ˇ
- "});
+ const a: ˇA = (
+ (ˇ
+ «const_functionˇ»(ˇ),
+ so«mˇ»et«hˇ»ing_ˇelse,ˇ
+ )ˇ
+ ˇ);ˇ
+ "});
cx.update_editor(|e, cx| e.newline_below(&NewlineBelow, cx));
cx.assert_editor_state(indoc! {"
- const a: A = (
+ const a: A = (
+ ˇ
+ (
ˇ
- (
- ˇ
- const_function(),
- ˇ
- ˇ
- something_else,
- ˇ
- ˇ
- ˇ
- ˇ
- )
+ const_function(),
ˇ
- );
- ˇ
+ ˇ
+ something_else,
+ ˇ
+ ˇ
+ ˇ
+ ˇ
+ )
ˇ
- "});
+ );
+ ˇ
+ ˇ
+ "});
}
#[gpui::test]
@@ -1427,26 +1426,26 @@ async fn test_tab(cx: &mut gpui::TestAppContext) {
});
});
cx.set_state(indoc! {"
- ˇabˇc
- ˇ🏀ˇ🏀ˇefg
- dˇ
- "});
+ ˇabˇc
+ ˇ🏀ˇ🏀ˇefg
+ dˇ
+ "});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
- ˇab ˇc
- ˇ🏀 ˇ🏀 ˇefg
- d ˇ
- "});
+ ˇab ˇc
+ ˇ🏀 ˇ🏀 ˇefg
+ d ˇ
+ "});
cx.set_state(indoc! {"
- a
- «🏀ˇ»🏀«🏀ˇ»🏀«🏀ˇ»
- "});
+ a
+ «🏀ˇ»🏀«🏀ˇ»🏀«🏀ˇ»
+ "});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
- a
- «🏀ˇ»🏀«🏀ˇ»🏀«🏀ˇ»
- "});
+ a
+ «🏀ˇ»🏀«🏀ˇ»🏀«🏀ˇ»
+ "});
}
#[gpui::test]
@@ -1466,45 +1465,45 @@ async fn test_tab_on_blank_line_auto_indents(cx: &mut gpui::TestAppContext) {
// a soft tab. cursors that are to the left of the suggested indent
// auto-indent their line.
cx.set_state(indoc! {"
- ˇ
- const a: B = (
- c(
- d(
- ˇ
- )
- ˇ
- ˇ )
- );
- "});
+ ˇ
+ const a: B = (
+ c(
+ d(
+ ˇ
+ )
+ ˇ
+ ˇ )
+ );
+ "});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
- ˇ
- const a: B = (
- c(
- d(
- ˇ
- )
+ ˇ
+ const a: B = (
+ c(
+ d(
ˇ
- ˇ)
- );
- "});
+ )
+ ˇ
+ ˇ)
+ );
+ "});
// handle auto-indent when there are multiple cursors on the same line
cx.set_state(indoc! {"
- const a: B = (
- c(
- ˇ ˇ
- ˇ )
- );
- "});
+ const a: B = (
+ c(
+ ˇ ˇ
+ ˇ )
+ );
+ "});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
- const a: B = (
- c(
- ˇ
- ˇ)
- );
- "});
+ const a: B = (
+ c(
+ ˇ
+ ˇ)
+ );
+ "});
}
#[gpui::test]
@@ -1512,68 +1511,68 @@ async fn test_indent_outdent(cx: &mut gpui::TestAppContext) {
let mut cx = EditorTestContext::new(cx);
cx.set_state(indoc! {"
- «oneˇ» «twoˇ»
- three
- four
- "});
+ «oneˇ» «twoˇ»
+ three
+ four
+ "});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
- «oneˇ» «twoˇ»
- three
- four
- "});
+ «oneˇ» «twoˇ»
+ three
+ four
+ "});
cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
cx.assert_editor_state(indoc! {"
- «oneˇ» «twoˇ»
- three
- four
- "});
+ «oneˇ» «twoˇ»
+ three
+ four
+ "});
// select across line ending
cx.set_state(indoc! {"
- one two
- t«hree
- ˇ» four
- "});
+ one two
+ t«hree
+ ˇ» four
+ "});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
- one two
- t«hree
- ˇ» four
- "});
+ one two
+ t«hree
+ ˇ» four
+ "});
cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
cx.assert_editor_state(indoc! {"
- one two
- t«hree
- ˇ» four
- "});
+ one two
+ t«hree
+ ˇ» four
+ "});
// Ensure that indenting/outdenting works when the cursor is at column 0.
cx.set_state(indoc! {"
- one two
- ˇthree
- four
- "});
+ one two
+ ˇthree
+ four
+ "});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
- one two
- ˇthree
- four
- "});
+ one two
+ ˇthree
+ four
+ "});
cx.set_state(indoc! {"
- one two
- ˇ three
- four
- "});
+ one two
+ ˇ three
+ four
+ "});
cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
cx.assert_editor_state(indoc! {"
- one two
- ˇthree
- four
- "});
+ one two
+ ˇthree
+ four
+ "});
}
#[gpui::test]
@@ -1587,90 +1586,90 @@ async fn test_indent_outdent_with_hard_tabs(cx: &mut gpui::TestAppContext) {
// select two ranges on one line
cx.set_state(indoc! {"
- «oneˇ» «twoˇ»
- three
- four
- "});
+ «oneˇ» «twoˇ»
+ three
+ four
+ "});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
- \t«oneˇ» «twoˇ»
- three
- four
- "});
+ \t«oneˇ» «twoˇ»
+ three
+ four
+ "});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
- \t\t«oneˇ» «twoˇ»
- three
- four
- "});
+ \t\t«oneˇ» «twoˇ»
+ three
+ four
+ "});
cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
cx.assert_editor_state(indoc! {"
- \t«oneˇ» «twoˇ»
- three
- four
- "});
+ \t«oneˇ» «twoˇ»
+ three
+ four
+ "});
cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
cx.assert_editor_state(indoc! {"
- «oneˇ» «twoˇ»
- three
- four
- "});
+ «oneˇ» «twoˇ»
+ three
+ four
+ "});
// select across a line ending
cx.set_state(indoc! {"
- one two
- t«hree
- ˇ»four
- "});
+ one two
+ t«hree
+ ˇ»four
+ "});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
- one two
- \tt«hree
- ˇ»four
- "});
+ one two
+ \tt«hree
+ ˇ»four
+ "});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
- one two
- \t\tt«hree
- ˇ»four
- "});
+ one two
+ \t\tt«hree
+ ˇ»four
+ "});
cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
cx.assert_editor_state(indoc! {"
- one two
- \tt«hree
- ˇ»four
- "});
+ one two
+ \tt«hree
+ ˇ»four
+ "});
cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
cx.assert_editor_state(indoc! {"
- one two
- t«hree
- ˇ»four
- "});
+ one two
+ t«hree
+ ˇ»four
+ "});
// Ensure that indenting/outdenting works when the cursor is at column 0.
cx.set_state(indoc! {"
- one two
- ˇthree
- four
- "});
+ one two
+ ˇthree
+ four
+ "});
cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
cx.assert_editor_state(indoc! {"
- one two
- ˇthree
- four
- "});
+ one two
+ ˇthree
+ four
+ "});
cx.update_editor(|e, cx| e.tab(&Tab, cx));
cx.assert_editor_state(indoc! {"
- one two
- \tˇthree
- four
- "});
+ one two
+ \tˇthree
+ four
+ "});
cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
cx.assert_editor_state(indoc! {"
- one two
- ˇthree
- four
- "});
+ one two
+ ˇthree
+ four
+ "});
}
#[gpui::test]
@@ -1739,21 +1738,21 @@ fn test_indent_outdent_with_excerpts(cx: &mut gpui::MutableAppContext) {
assert_eq!(
editor.text(cx),
indoc! {"
- a = 1
- b = 2
+ a = 1
+ b = 2
- const c: usize = 3;
- "}
+ const c: usize = 3;
+ "}
);
select_ranges(
&mut editor,
indoc! {"
- «aˇ» = 1
- b = 2
+ «aˇ» = 1
+ b = 2
- «const c:ˇ» usize = 3;
- "},
+ «const c:ˇ» usize = 3;
+ "},
cx,
);
@@ -1761,22 +1760,22 @@ fn test_indent_outdent_with_excerpts(cx: &mut gpui::MutableAppContext) {
assert_text_with_selections(
&mut editor,
indoc! {"
- «aˇ» = 1
- b = 2
+ «aˇ» = 1
+ b = 2
- «const c:ˇ» usize = 3;
- "},
+ «const c:ˇ» usize = 3;
+ "},
cx,
);
editor.tab_prev(&TabPrev, cx);
assert_text_with_selections(
&mut editor,
indoc! {"
- «aˇ» = 1
- b = 2
+ «aˇ» = 1
+ b = 2
- «const c:ˇ» usize = 3;
- "},
+ «const c:ˇ» usize = 3;
+ "},
cx,
);
@@ -1790,45 +1789,45 @@ async fn test_backspace(cx: &mut gpui::TestAppContext) {
// Basic backspace
cx.set_state(indoc! {"
- onˇe two three
- fou«rˇ» five six
- seven «ˇeight nine
- »ten
- "});
+ onˇe two three
+ fou«rˇ» five six
+ seven «ˇeight nine
+ »ten
+ "});
cx.update_editor(|e, cx| e.backspace(&Backspace, cx));
cx.assert_editor_state(indoc! {"
- oˇe two three
- fouˇ five six
- seven ˇten
- "});
+ oˇe two three
+ fouˇ five six
+ seven ˇten
+ "});
// Test backspace inside and around indents
cx.set_state(indoc! {"
- zero
- ˇone
- ˇtwo
- ˇ ˇ ˇ three
- ˇ ˇ four
- "});
- cx.update_editor(|e, cx| e.backspace(&Backspace, cx));
- cx.assert_editor_state(indoc! {"
- zero
+ zero
ˇone
ˇtwo
- ˇ threeˇ four
- "});
+ ˇ ˇ ˇ three
+ ˇ ˇ four
+ "});
+ cx.update_editor(|e, cx| e.backspace(&Backspace, cx));
+ cx.assert_editor_state(indoc! {"
+ zero
+ ˇone
+ ˇtwo
+ ˇ threeˇ four
+ "});
// Test backspace with line_mode set to true
cx.update_editor(|e, _| e.selections.line_mode = true);
cx.set_state(indoc! {"
- The ˇquick ˇbrown
- fox jumps over
- the lazy dog
- ˇThe qu«ick bˇ»rown"});
+ The ˇquick ˇbrown
+ fox jumps over
+ the lazy dog
+ ˇThe qu«ick bˇ»rown"});
cx.update_editor(|e, cx| e.backspace(&Backspace, cx));
cx.assert_editor_state(indoc! {"
- ˇfox jumps over
- the lazy dogˇ"});
+ ˇfox jumps over
+ the lazy dogˇ"});
}
#[gpui::test]
@@ -1836,25 +1835,25 @@ async fn test_delete(cx: &mut gpui::TestAppContext) {
let mut cx = EditorTestContext::new(cx);
cx.set_state(indoc! {"
- onˇe two three
- fou«rˇ» five six
- seven «ˇeight nine
- »ten
- "});
+ onˇe two three
+ fou«rˇ» five six
+ seven «ˇeight nine
+ »ten
+ "});
cx.update_editor(|e, cx| e.delete(&Delete, cx));
cx.assert_editor_state(indoc! {"
- onˇ two three
- fouˇ five six
- seven ˇten
- "});
+ onˇ two three
+ fouˇ five six
+ seven ˇten
+ "});
// Test backspace with line_mode set to true
cx.update_editor(|e, _| e.selections.line_mode = true);
cx.set_state(indoc! {"
- The ˇquick ˇbrown
- fox «ˇjum»ps over
- the lazy dog
- ˇThe qu«ick bˇ»rown"});
+ The ˇquick ˇbrown
+ fox «ˇjum»ps over
+ the lazy dog
+ ˇThe qu«ick bˇ»rown"});
cx.update_editor(|e, cx| e.backspace(&Backspace, cx));
cx.assert_editor_state("ˇthe lazy dogˇ");
}
@@ -2191,57 +2190,57 @@ async fn test_clipboard(cx: &mut gpui::TestAppContext) {
e.handle_input(") ", cx);
});
cx.assert_editor_state(indoc! {"
- ( one✅
- three
- five ) ˇtwo one✅ four three six five ( one✅
- three
- five ) ˇ"});
+ ( one✅
+ three
+ five ) ˇtwo one✅ four three six five ( one✅
+ three
+ five ) ˇ"});
// Cut with three selections, one of which is full-line.
cx.set_state(indoc! {"
- 1«2ˇ»3
- 4ˇ567
- «8ˇ»9"});
+ 1«2ˇ»3
+ 4ˇ567
+ «8ˇ»9"});
cx.update_editor(|e, cx| e.cut(&Cut, cx));
cx.assert_editor_state(indoc! {"
- 1ˇ3
- ˇ9"});
+ 1ˇ3
+ ˇ9"});
// Paste with three selections, noticing how the copied selection that was full-line
// gets inserted before the second cursor.
cx.set_state(indoc! {"
- 1ˇ3
- 9ˇ
- «oˇ»ne"});
+ 1ˇ3
+ 9ˇ
+ «oˇ»ne"});
cx.update_editor(|e, cx| e.paste(&Paste, cx));
cx.assert_editor_state(indoc! {"
- 12ˇ3
- 4567
- 9ˇ
- 8ˇne"});
+ 12ˇ3
+ 4567
+ 9ˇ
+ 8ˇne"});
// Copy with a single cursor only, which writes the whole line into the clipboard.
cx.set_state(indoc! {"
- The quick brown
- fox juˇmps over
- the lazy dog"});
+ The quick brown
+ fox juˇmps over
+ the lazy dog"});
cx.update_editor(|e, cx| e.copy(&Copy, cx));
cx.cx.assert_clipboard_content(Some("fox jumps over\n"));
// Paste with three selections, noticing how the copied full-line selection is inserted
// before the empty selections but replaces the selection that is non-empty.
cx.set_state(indoc! {"
- Tˇhe quick brown
- «foˇ»x jumps over
- tˇhe lazy dog"});
+ Tˇhe quick brown
+ «foˇ»x jumps over
+ tˇhe lazy dog"});
cx.update_editor(|e, cx| e.paste(&Paste, cx));
cx.assert_editor_state(indoc! {"
- fox jumps over
- Tˇhe quick brown
- fox jumps over
- ˇx jumps over
- fox jumps over
- tˇhe lazy dog"});
+ fox jumps over
+ Tˇhe quick brown
+ fox jumps over
+ ˇx jumps over
+ fox jumps over
+ tˇhe lazy dog"});
}
#[gpui::test]
@@ -2255,105 +2254,105 @@ async fn test_paste_multiline(cx: &mut gpui::TestAppContext) {
// Cut an indented block, without the leading whitespace.
cx.set_state(indoc! {"
- const a: B = (
- c(),
- «d(
- e,
- f
- )ˇ»
- );
- "});
+ const a: B = (
+ c(),
+ «d(
+ e,
+ f
+ )ˇ»
+ );
+ "});
cx.update_editor(|e, cx| e.cut(&Cut, cx));
cx.assert_editor_state(indoc! {"
- const a: B = (
- c(),
- ˇ
- );
- "});
+ const a: B = (
+ c(),
+ ˇ
+ );
+ "});
// Paste it at the same position.
cx.update_editor(|e, cx| e.paste(&Paste, cx));
cx.assert_editor_state(indoc! {"
- const a: B = (
- c(),
- d(
- e,
- f
- )ˇ
- );
- "});
+ const a: B = (
+ c(),
+ d(
+ e,
+ f
+ )ˇ
+ );
+ "});
// Paste it at a line with a lower indent level.
cx.set_state(indoc! {"
- ˇ
- const a: B = (
- c(),
- );
- "});
+ ˇ
+ const a: B = (
+ c(),
+ );
+ "});
cx.update_editor(|e, cx| e.paste(&Paste, cx));
cx.assert_editor_state(indoc! {"
- d(
- e,
- f
- )ˇ
- const a: B = (
- c(),
- );
- "});
+ d(
+ e,
+ f
+ )ˇ
+ const a: B = (
+ c(),
+ );
+ "});
// Cut an indented block, with the leading whitespace.
cx.set_state(indoc! {"
- const a: B = (
- c(),
- « d(
- e,
- f
- )
- ˇ»);
- "});
+ const a: B = (
+ c(),
+ « d(
+ e,
+ f
+ )
+ ˇ»);
+ "});
cx.update_editor(|e, cx| e.cut(&Cut, cx));
cx.assert_editor_state(indoc! {"
- const a: B = (
- c(),
- ˇ);
- "});
+ const a: B = (
+ c(),
+ ˇ);
+ "});
// Paste it at the same position.
cx.update_editor(|e, cx| e.paste(&Paste, cx));
cx.assert_editor_state(indoc! {"
- const a: B = (
- c(),
- d(
- e,
- f
- )
- ˇ);
- "});
+ const a: B = (
+ c(),
+ d(
+ e,
+ f
+ )
+ ˇ);
+ "});
// Paste it at a line with a higher indent level.
cx.set_state(indoc! {"
- const a: B = (
- c(),
- d(
- e,
- fˇ
- )
- );
- "});
+ const a: B = (
+ c(),
+ d(
+ e,
+ fˇ
+ )
+ );
+ "});
cx.update_editor(|e, cx| e.paste(&Paste, cx));
cx.assert_editor_state(indoc! {"
- const a: B = (
- c(),
- d(
+ const a: B = (
+ c(),
+ d(
+ e,
+ f d(
e,
- f d(
- e,
- f
- )
- ˇ
+ f
)
- );
- "});
+ ˇ
+ )
+ );
+ "});
}
#[gpui::test]
@@ -8,10 +8,7 @@ pub mod worktree;
mod project_tests;
use anyhow::{anyhow, Context, Result};
-use client::{
- proto::{self},
- Client, PeerId, TypedEnvelope, User, UserStore,
-};
+use client::{proto, Client, PeerId, TypedEnvelope, User, UserStore};
use clock::ReplicaId;
use collections::{hash_map, BTreeMap, HashMap, HashSet};
use futures::{future::Shared, AsyncWriteExt, Future, FutureExt, StreamExt, TryFutureExt};
@@ -66,7 +63,7 @@ use std::{
time::Instant,
};
use thiserror::Error;
-use util::{post_inc, ResultExt, TryFutureExt as _};
+use util::{defer, post_inc, ResultExt, TryFutureExt as _};
pub use db::Db;
pub use fs::*;
@@ -128,6 +125,7 @@ pub struct Project {
opened_buffers: HashMap<u64, OpenBuffer>,
incomplete_buffers: HashMap<u64, ModelHandle<Buffer>>,
buffer_snapshots: HashMap<u64, Vec<(i32, TextBufferSnapshot)>>,
+ buffers_being_formatted: HashSet<usize>,
nonce: u128,
initialized_persistent_state: bool,
_maintain_buffer_languages: Task<()>,
@@ -512,6 +510,7 @@ impl Project {
language_server_statuses: Default::default(),
last_workspace_edits_by_language_server: Default::default(),
language_server_settings: Default::default(),
+ buffers_being_formatted: Default::default(),
next_language_server_id: 0,
nonce: StdRng::from_entropy().gen(),
initialized_persistent_state: false,
@@ -627,6 +626,7 @@ impl Project {
last_workspace_edits_by_language_server: Default::default(),
next_language_server_id: 0,
opened_buffers: Default::default(),
+ buffers_being_formatted: Default::default(),
buffer_snapshots: Default::default(),
nonce: StdRng::from_entropy().gen(),
initialized_persistent_state: false,
@@ -3113,7 +3113,26 @@ impl Project {
.await?;
}
- for (buffer, buffer_abs_path, language_server) in local_buffers {
+ // Do not allow multiple concurrent formatting requests for the
+ // same buffer.
+ this.update(&mut cx, |this, _| {
+ local_buffers
+ .retain(|(buffer, _, _)| this.buffers_being_formatted.insert(buffer.id()));
+ });
+ let _cleanup = defer({
+ let this = this.clone();
+ let mut cx = cx.clone();
+ let local_buffers = &local_buffers;
+ move || {
+ this.update(&mut cx, |this, _| {
+ for (buffer, _, _) in local_buffers {
+ this.buffers_being_formatted.remove(&buffer.id());
+ }
+ });
+ }
+ });
+
+ for (buffer, buffer_abs_path, language_server) in &local_buffers {
let (format_on_save, formatter, tab_size) = buffer.read_with(&cx, |buffer, cx| {
let settings = cx.global::<Settings>();
let language_name = buffer.language().map(|language| language.name());
@@ -3165,7 +3184,7 @@ impl Project {
buffer.forget_transaction(transaction.id)
});
}
- project_transaction.0.insert(buffer, transaction);
+ project_transaction.0.insert(buffer.clone(), transaction);
}
}