Merge remote-tracking branch 'origin/main' into window-handles

This commit is contained in:
Nathan Sobo 2023-08-07 22:07:20 -06:00
commit d687c3d81f
11 changed files with 222 additions and 33 deletions

12
Cargo.lock generated
View File

@ -1655,6 +1655,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
[[package]]
name = "convert_case"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "copilot"
version = "0.1.0"
@ -2145,7 +2154,7 @@ version = "0.99.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
dependencies = [
"convert_case",
"convert_case 0.4.0",
"proc-macro2",
"quote",
"rustc_version 0.4.0",
@ -2333,6 +2342,7 @@ dependencies = [
"clock",
"collections",
"context_menu",
"convert_case 0.6.0",
"copilot",
"ctor",
"db",

View File

@ -47,6 +47,7 @@ workspace = { path = "../workspace" }
aho-corasick = "0.7"
anyhow.workspace = true
convert_case = "0.6.0"
futures.workspace = true
indoc = "1.0.4"
itertools = "0.10"
@ -56,12 +57,12 @@ ordered-float.workspace = true
parking_lot.workspace = true
postage.workspace = true
pulldown-cmark = { version = "0.9.2", default-features = false }
rand.workspace = true
schemars.workspace = true
serde.workspace = true
serde_derive.workspace = true
smallvec.workspace = true
smol.workspace = true
rand.workspace = true
tree-sitter-rust = { workspace = true, optional = true }
tree-sitter-html = { workspace = true, optional = true }

View File

@ -28,6 +28,7 @@ use blink_manager::BlinkManager;
use client::{ClickhouseEvent, TelemetrySettings};
use clock::{Global, ReplicaId};
use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque};
use convert_case::{Case, Casing};
use copilot::Copilot;
pub use display_map::DisplayPoint;
use display_map::*;
@ -231,6 +232,13 @@ actions!(
SortLinesCaseInsensitive,
ReverseLines,
ShuffleLines,
ConvertToUpperCase,
ConvertToLowerCase,
ConvertToTitleCase,
ConvertToSnakeCase,
ConvertToKebabCase,
ConvertToUpperCamelCase,
ConvertToLowerCamelCase,
Transpose,
Cut,
Copy,
@ -353,6 +361,13 @@ pub fn init(cx: &mut AppContext) {
cx.add_action(Editor::sort_lines_case_insensitive);
cx.add_action(Editor::reverse_lines);
cx.add_action(Editor::shuffle_lines);
cx.add_action(Editor::convert_to_upper_case);
cx.add_action(Editor::convert_to_lower_case);
cx.add_action(Editor::convert_to_title_case);
cx.add_action(Editor::convert_to_snake_case);
cx.add_action(Editor::convert_to_kebab_case);
cx.add_action(Editor::convert_to_upper_camel_case);
cx.add_action(Editor::convert_to_lower_camel_case);
cx.add_action(Editor::delete_to_previous_word_start);
cx.add_action(Editor::delete_to_previous_subword_start);
cx.add_action(Editor::delete_to_next_word_end);
@ -4306,6 +4321,97 @@ impl Editor {
});
}
pub fn convert_to_upper_case(&mut self, _: &ConvertToUpperCase, cx: &mut ViewContext<Self>) {
self.manipulate_text(cx, |text| text.to_uppercase())
}
pub fn convert_to_lower_case(&mut self, _: &ConvertToLowerCase, cx: &mut ViewContext<Self>) {
self.manipulate_text(cx, |text| text.to_lowercase())
}
pub fn convert_to_title_case(&mut self, _: &ConvertToTitleCase, cx: &mut ViewContext<Self>) {
self.manipulate_text(cx, |text| text.to_case(Case::Title))
}
pub fn convert_to_snake_case(&mut self, _: &ConvertToSnakeCase, cx: &mut ViewContext<Self>) {
self.manipulate_text(cx, |text| text.to_case(Case::Snake))
}
pub fn convert_to_kebab_case(&mut self, _: &ConvertToKebabCase, cx: &mut ViewContext<Self>) {
self.manipulate_text(cx, |text| text.to_case(Case::Kebab))
}
pub fn convert_to_upper_camel_case(
&mut self,
_: &ConvertToUpperCamelCase,
cx: &mut ViewContext<Self>,
) {
self.manipulate_text(cx, |text| text.to_case(Case::UpperCamel))
}
pub fn convert_to_lower_camel_case(
&mut self,
_: &ConvertToLowerCamelCase,
cx: &mut ViewContext<Self>,
) {
self.manipulate_text(cx, |text| text.to_case(Case::Camel))
}
fn manipulate_text<Fn>(&mut self, cx: &mut ViewContext<Self>, mut callback: Fn)
where
Fn: FnMut(&str) -> String,
{
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let buffer = self.buffer.read(cx).snapshot(cx);
let mut new_selections = Vec::new();
let mut edits = Vec::new();
let mut selection_adjustment = 0i32;
for selection in self.selections.all::<usize>(cx) {
let selection_is_empty = selection.is_empty();
let (start, end) = if selection_is_empty {
let word_range = movement::surrounding_word(
&display_map,
selection.start.to_display_point(&display_map),
);
let start = word_range.start.to_offset(&display_map, Bias::Left);
let end = word_range.end.to_offset(&display_map, Bias::Left);
(start, end)
} else {
(selection.start, selection.end)
};
let text = buffer.text_for_range(start..end).collect::<String>();
let old_length = text.len() as i32;
let text = callback(&text);
new_selections.push(Selection {
start: (start as i32 - selection_adjustment) as usize,
end: ((start + text.len()) as i32 - selection_adjustment) as usize,
goal: SelectionGoal::None,
..selection
});
selection_adjustment += old_length - text.len() as i32;
edits.push((start..end, text));
}
self.transact(cx, |this, cx| {
this.buffer.update(cx, |buffer, cx| {
buffer.edit(edits, None, cx);
});
this.change_selections(Some(Autoscroll::fit()), cx, |s| {
s.select(new_selections);
});
this.request_autoscroll(Autoscroll::fit(), cx);
});
}
pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let buffer = &display_map.buffer_snapshot;

View File

@ -2698,6 +2698,84 @@ async fn test_manipulate_lines_with_multi_selection(cx: &mut TestAppContext) {
"});
}
#[gpui::test]
async fn test_manipulate_text(cx: &mut TestAppContext) {
init_test(cx, |_| {});
let mut cx = EditorTestContext::new(cx).await;
// Test convert_to_upper_case()
cx.set_state(indoc! {"
«hello worldˇ»
"});
cx.update_editor(|e, cx| e.convert_to_upper_case(&ConvertToUpperCase, cx));
cx.assert_editor_state(indoc! {"
«HELLO WORLDˇ»
"});
// Test convert_to_lower_case()
cx.set_state(indoc! {"
«HELLO WORLDˇ»
"});
cx.update_editor(|e, cx| e.convert_to_lower_case(&ConvertToLowerCase, cx));
cx.assert_editor_state(indoc! {"
«hello worldˇ»
"});
// From here on out, test more complex cases of manipulate_text()
// Test no selection case - should affect words cursors are in
// Cursor at beginning, middle, and end of word
cx.set_state(indoc! {"
ˇhello big beauˇtiful worldˇ
"});
cx.update_editor(|e, cx| e.convert_to_upper_case(&ConvertToUpperCase, cx));
cx.assert_editor_state(indoc! {"
«HELLOˇ» big «BEAUTIFULˇ» «WORLDˇ»
"});
// Test multiple selections on a single line and across multiple lines
cx.set_state(indoc! {"
«Theˇ» quick «brown
foxˇ» jumps «overˇ»
the «lazyˇ» dog
"});
cx.update_editor(|e, cx| e.convert_to_upper_case(&ConvertToUpperCase, cx));
cx.assert_editor_state(indoc! {"
«THEˇ» quick «BROWN
FOXˇ» jumps «OVERˇ»
the «LAZYˇ» dog
"});
// Test case where text length grows
cx.set_state(indoc! {"
«tschüߡ»
"});
cx.update_editor(|e, cx| e.convert_to_upper_case(&ConvertToUpperCase, cx));
cx.assert_editor_state(indoc! {"
«TSCHÜSSˇ»
"});
// Test to make sure we don't crash when text shrinks
cx.set_state(indoc! {"
aaa_bbbˇ
"});
cx.update_editor(|e, cx| e.convert_to_lower_camel_case(&ConvertToLowerCamelCase, cx));
cx.assert_editor_state(indoc! {"
«aaaBbbˇ»
"});
// Test to make sure we all aware of the fact that each word can grow and shrink
// Final selections should be aware of this fact
cx.set_state(indoc! {"
aaa_bˇbb bbˇb_ccc ˇccc_ddd
"});
cx.update_editor(|e, cx| e.convert_to_lower_camel_case(&ConvertToLowerCamelCase, cx));
cx.assert_editor_state(indoc! {"
«aaaBbbˇ» «bbbCccˇ» «cccDddˇ»
"});
}
#[gpui::test]
fn test_duplicate_line(cx: &mut TestAppContext) {
init_test(cx, |_| {});

View File

@ -4088,6 +4088,7 @@ impl AnyWindowHandle {
self.update(cx, |cx| cx.remove_window())
}
#[cfg(any(test, feature = "test-support"))]
pub fn simulate_activation(&self, cx: &mut TestAppContext) {
self.update(cx, |cx| {
let other_window_ids = cx
@ -4105,6 +4106,7 @@ impl AnyWindowHandle {
});
}
#[cfg(any(test, feature = "test-support"))]
pub fn simulate_deactivation(&self, cx: &mut TestAppContext) {
self.update(cx, |cx| {
cx.window_changed_active_status(self.window_id, false);

View File

@ -182,8 +182,8 @@ impl CachedLspAdapter {
self.adapter.workspace_configuration(cx)
}
pub async fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) {
self.adapter.process_diagnostics(params).await
pub fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) {
self.adapter.process_diagnostics(params)
}
pub async fn process_completion(&self, completion_item: &mut lsp::CompletionItem) {
@ -262,7 +262,7 @@ pub trait LspAdapter: 'static + Send + Sync {
container_dir: PathBuf,
) -> Option<LanguageServerBinary>;
async fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
async fn process_completion(&self, _: &mut lsp::CompletionItem) {}
@ -1487,12 +1487,6 @@ impl Language {
None
}
pub async fn process_diagnostics(&self, diagnostics: &mut lsp::PublishDiagnosticsParams) {
for adapter in &self.adapters {
adapter.process_diagnostics(diagnostics).await;
}
}
pub async fn process_completion(self: &Arc<Self>, completion: &mut lsp::CompletionItem) {
for adapter in &self.adapters {
adapter.process_completion(completion).await;
@ -1756,7 +1750,7 @@ impl LspAdapter for Arc<FakeLspAdapter> {
unreachable!();
}
async fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
async fn disk_based_diagnostic_sources(&self) -> Vec<String> {
self.disk_based_diagnostics_sources.clone()

View File

@ -2769,24 +2769,21 @@ impl Project {
language_server
.on_notification::<lsp::notification::PublishDiagnostics, _>({
let adapter = adapter.clone();
move |mut params, cx| {
move |mut params, mut cx| {
let this = this;
let adapter = adapter.clone();
cx.spawn(|mut cx| async move {
adapter.process_diagnostics(&mut params).await;
if let Some(this) = this.upgrade(&cx) {
this.update(&mut cx, |this, cx| {
this.update_diagnostics(
server_id,
params,
&adapter.disk_based_diagnostic_sources,
cx,
)
.log_err();
});
}
})
.detach();
adapter.process_diagnostics(&mut params);
if let Some(this) = this.upgrade(&cx) {
this.update(&mut cx, |this, cx| {
this.update_diagnostics(
server_id,
params,
&adapter.disk_based_diagnostic_sources,
cx,
)
.log_err();
});
}
}
})
.detach();

View File

@ -294,7 +294,7 @@ mod tests {
}
#[test]
fn test_path_suffix() {
fn test_icon_suffix() {
// No dots in name
let path = Path::new("/a/b/c/file_name.rs");
assert_eq!(path.icon_suffix(), Some("rs"));

View File

@ -1,5 +1,6 @@
name = "Shell Script"
path_suffixes = [".sh", ".bash", ".bashrc", ".bash_profile", ".bash_aliases", ".bash_logout", ".profile", ".zsh", ".zshrc", ".zshenv", ".zsh_profile", ".zsh_aliases", ".zsh_histfile", ".zlogin"]
path_suffixes = ["sh", "bash", "bashrc", "bash_profile", "bash_aliases", "bash_logout", "profile", "zsh", "zshrc", "zshenv", "zsh_profile", "zsh_aliases", "zsh_histfile", "zlogin"]
line_comment = "# "
first_line_pattern = "^#!.*\\b(?:ba|z)?sh\\b"
brackets = [
{ start = "[", end = "]", close = true, newline = false },

View File

@ -102,7 +102,7 @@ impl LspAdapter for RustLspAdapter {
Some("rust-analyzer/flycheck".into())
}
async fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) {
fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) {
lazy_static! {
static ref REGEX: Regex = Regex::new("(?m)`([^`]+)\n`$").unwrap();
}
@ -310,7 +310,7 @@ mod tests {
},
],
};
RustLspAdapter.process_diagnostics(&mut params).await;
RustLspAdapter.process_diagnostics(&mut params);
assert_eq!(params.diagnostics[0].message, "use of moved value `a`");

View File

@ -1,5 +1,5 @@
name = "TOML"
path_suffixes = ["toml"]
path_suffixes = ["Cargo.lock", "toml"]
line_comment = "# "
autoclose_before = ",]}"
brackets = [