Merge branch 'main' into copilot-disabled-globs

This commit is contained in:
Max Brunsfeld 2023-05-03 10:36:12 -07:00
commit 9d41f83b1b
81 changed files with 1649 additions and 1545 deletions

View file

@ -23,6 +23,7 @@ test-support = [
]
[dependencies]
client = { path = "../client" }
clock = { path = "../clock" }
copilot = { path = "../copilot" }
db = { path = "../db" }

View file

@ -22,6 +22,7 @@ pub mod test;
use aho_corasick::AhoCorasick;
use anyhow::{anyhow, Result};
use blink_manager::BlinkManager;
use client::ClickhouseEvent;
use clock::ReplicaId;
use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque};
use copilot::Copilot;
@ -51,8 +52,8 @@ use itertools::Itertools;
pub use language::{char_kind, CharKind};
use language::{
AutoindentMode, BracketPair, Buffer, CodeAction, CodeLabel, Completion, CursorShape,
Diagnostic, DiagnosticSeverity, IndentKind, IndentSize, Language, OffsetRangeExt, OffsetUtf16,
Point, Selection, SelectionGoal, TransactionId,
Diagnostic, DiagnosticSeverity, File, IndentKind, IndentSize, Language, OffsetRangeExt,
OffsetUtf16, Point, Selection, SelectionGoal, TransactionId,
};
use link_go_to_definition::{
hide_link_definition, show_link_definition, LinkDefinitionKind, LinkGoToDefinitionState,
@ -808,10 +809,13 @@ impl CompletionsMenu {
},
)
.with_cursor_style(CursorStyle::PointingHand)
.on_down(MouseButton::Left, move |_, _, cx| {
cx.dispatch_action(ConfirmCompletion {
item_ix: Some(item_ix),
});
.on_down(MouseButton::Left, move |_, this, cx| {
this.confirm_completion(
&ConfirmCompletion {
item_ix: Some(item_ix),
},
cx,
);
})
.into_any(),
);
@ -969,9 +973,23 @@ impl CodeActionsMenu {
.with_style(item_style)
})
.with_cursor_style(CursorStyle::PointingHand)
.on_down(MouseButton::Left, move |_, _, cx| {
cx.dispatch_action(ConfirmCodeAction {
item_ix: Some(item_ix),
.on_down(MouseButton::Left, move |_, this, cx| {
let workspace = this
.workspace
.as_ref()
.and_then(|(workspace, _)| workspace.upgrade(cx));
cx.window_context().defer(move |cx| {
if let Some(workspace) = workspace {
workspace.update(cx, |workspace, cx| {
if let Some(task) = Editor::confirm_code_action(
workspace,
&Default::default(),
cx,
) {
task.detach_and_log_err(cx);
}
});
}
});
})
.into_any(),
@ -1295,7 +1313,7 @@ impl Editor {
cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
}
this.report_event("open editor", cx);
this.report_editor_event("open", cx);
this
}
@ -1330,6 +1348,10 @@ impl Editor {
&self.buffer
}
fn workspace(&self, cx: &AppContext) -> Option<ViewHandle<Workspace>> {
self.workspace.as_ref()?.0.upgrade(cx)
}
pub fn title<'a>(&self, cx: &'a AppContext) -> Cow<'a, str> {
self.buffer().read(cx).title(cx)
}
@ -1356,6 +1378,10 @@ impl Editor {
self.buffer.read(cx).language_at(point, cx)
}
pub fn file_at<'a, T: ToOffset>(&self, point: T, cx: &'a AppContext) -> Option<Arc<dyn File>> {
self.buffer.read(cx).read(cx).file_at(point).cloned()
}
pub fn active_excerpt(
&self,
cx: &AppContext,
@ -3148,10 +3174,13 @@ impl Editor {
})
.with_cursor_style(CursorStyle::PointingHand)
.with_padding(Padding::uniform(3.))
.on_down(MouseButton::Left, |_, _, cx| {
cx.dispatch_action(ToggleCodeActions {
deployed_from_indicator: true,
});
.on_down(MouseButton::Left, |_, this, cx| {
this.toggle_code_actions(
&ToggleCodeActions {
deployed_from_indicator: true,
},
cx,
);
})
.into_any(),
)
@ -3209,11 +3238,13 @@ impl Editor {
.with_cursor_style(CursorStyle::PointingHand)
.with_padding(Padding::uniform(3.))
.on_click(MouseButton::Left, {
move |_, _, cx| {
cx.dispatch_any_action(match fold_status {
FoldStatus::Folded => Box::new(UnfoldAt { buffer_row }),
FoldStatus::Foldable => Box::new(FoldAt { buffer_row }),
});
move |_, editor, cx| match fold_status {
FoldStatus::Folded => {
editor.unfold_at(&UnfoldAt { buffer_row }, cx);
}
FoldStatus::Foldable => {
editor.fold_at(&FoldAt { buffer_row }, cx);
}
}
})
.into_any()
@ -5572,93 +5603,77 @@ impl Editor {
}
}
pub fn go_to_definition(
workspace: &mut Workspace,
_: &GoToDefinition,
cx: &mut ViewContext<Workspace>,
) {
Self::go_to_definition_of_kind(GotoDefinitionKind::Symbol, workspace, cx);
pub fn go_to_definition(&mut self, _: &GoToDefinition, cx: &mut ViewContext<Self>) {
self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, cx);
}
pub fn go_to_type_definition(
workspace: &mut Workspace,
_: &GoToTypeDefinition,
cx: &mut ViewContext<Workspace>,
) {
Self::go_to_definition_of_kind(GotoDefinitionKind::Type, workspace, cx);
pub fn go_to_type_definition(&mut self, _: &GoToTypeDefinition, cx: &mut ViewContext<Self>) {
self.go_to_definition_of_kind(GotoDefinitionKind::Type, cx);
}
fn go_to_definition_of_kind(
kind: GotoDefinitionKind,
workspace: &mut Workspace,
cx: &mut ViewContext<Workspace>,
) {
let active_item = workspace.active_item(cx);
let editor_handle = if let Some(editor) = active_item
.as_ref()
.and_then(|item| item.act_as::<Self>(cx))
{
editor
} else {
return;
};
let editor = editor_handle.read(cx);
let buffer = editor.buffer.read(cx);
let head = editor.selections.newest::<usize>(cx).head();
fn go_to_definition_of_kind(&mut self, kind: GotoDefinitionKind, cx: &mut ViewContext<Self>) {
let Some(workspace) = self.workspace(cx) else { return };
let buffer = self.buffer.read(cx);
let head = self.selections.newest::<usize>(cx).head();
let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
text_anchor
} else {
return;
};
let project = workspace.project().clone();
let project = workspace.read(cx).project().clone();
let definitions = project.update(cx, |project, cx| match kind {
GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx),
GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx),
});
cx.spawn_labeled("Fetching Definition...", |workspace, mut cx| async move {
cx.spawn_labeled("Fetching Definition...", |editor, mut cx| async move {
let definitions = definitions.await?;
workspace.update(&mut cx, |workspace, cx| {
Editor::navigate_to_definitions(workspace, editor_handle, definitions, cx);
editor.update(&mut cx, |editor, cx| {
editor.navigate_to_definitions(definitions, cx);
})?;
Ok::<(), anyhow::Error>(())
})
.detach_and_log_err(cx);
}
pub fn navigate_to_definitions(
workspace: &mut Workspace,
editor_handle: ViewHandle<Editor>,
definitions: Vec<LocationLink>,
cx: &mut ViewContext<Workspace>,
&mut self,
mut definitions: Vec<LocationLink>,
cx: &mut ViewContext<Editor>,
) {
let pane = workspace.active_pane().clone();
let Some(workspace) = self.workspace(cx) else { return };
let pane = workspace.read(cx).active_pane().clone();
// If there is one definition, just open it directly
if let [definition] = definitions.as_slice() {
if definitions.len() == 1 {
let definition = definitions.pop().unwrap();
let range = definition
.target
.range
.to_offset(definition.target.buffer.read(cx));
let target_editor_handle =
workspace.open_project_item(definition.target.buffer.clone(), cx);
target_editor_handle.update(cx, |target_editor, cx| {
// When selecting a definition in a different buffer, disable the nav history
// to avoid creating a history entry at the previous cursor location.
if editor_handle != target_editor_handle {
pane.update(cx, |pane, _| pane.disable_history());
}
target_editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
if Some(&definition.target.buffer) == self.buffer.read(cx).as_singleton().as_ref() {
self.change_selections(Some(Autoscroll::fit()), cx, |s| {
s.select_ranges([range]);
});
pane.update(cx, |pane, _| pane.enable_history());
});
} else {
cx.window_context().defer(move |cx| {
let target_editor: ViewHandle<Self> = workspace.update(cx, |workspace, cx| {
workspace.open_project_item(definition.target.buffer.clone(), cx)
});
target_editor.update(cx, |target_editor, cx| {
// When selecting a definition in a different buffer, disable the nav history
// to avoid creating a history entry at the previous cursor location.
pane.update(cx, |pane, _| pane.disable_history());
target_editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
s.select_ranges([range]);
});
pane.update(cx, |pane, _| pane.enable_history());
});
});
}
} else if !definitions.is_empty() {
let replica_id = editor_handle.read(cx).replica_id(cx);
let replica_id = self.replica_id(cx);
let title = definitions
.iter()
.find(|definition| definition.origin.is_some())
@ -5678,7 +5693,9 @@ impl Editor {
.into_iter()
.map(|definition| definition.target)
.collect();
Self::open_locations_in_multibuffer(workspace, locations, replica_id, title, cx)
workspace.update(cx, |workspace, cx| {
Self::open_locations_in_multibuffer(workspace, locations, replica_id, title, cx)
})
}
}
@ -6834,7 +6851,7 @@ impl Editor {
.collect()
}
fn report_event(&self, name: &str, cx: &AppContext) {
fn report_editor_event(&self, name: &'static str, cx: &AppContext) {
if let Some((project, file)) = self.project.as_ref().zip(
self.buffer
.read(cx)
@ -6846,11 +6863,31 @@ impl Editor {
let extension = Path::new(file.file_name(cx))
.extension()
.and_then(|e| e.to_str());
project.read(cx).client().report_event(
name,
json!({ "File Extension": extension, "Vim Mode": settings.vim_mode }),
let telemetry = project.read(cx).client().telemetry().clone();
telemetry.report_mixpanel_event(
match name {
"open" => "open editor",
"save" => "save editor",
_ => name,
},
json!({ "File Extension": extension, "Vim Mode": settings.vim_mode, "In Clickhouse": true }),
settings.telemetry(),
);
let event = ClickhouseEvent::Editor {
file_extension: extension.map(ToString::to_string),
vim_mode: settings.vim_mode,
operation: name,
copilot_enabled: settings.features.copilot,
copilot_enabled_for_language: settings.show_copilot_suggestions(
self.language_at(0, cx)
.map(|language| language.name())
.as_deref(),
self.file_at(0, cx)
.map(|file| file.path().clone())
.as_deref(),
),
};
telemetry.report_clickhouse_event(event, settings.telemetry())
}
}
@ -7494,8 +7531,16 @@ impl Deref for EditorStyle {
pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> RenderBlock {
let mut highlighted_lines = Vec::new();
for line in diagnostic.message.lines() {
highlighted_lines.push(highlight_diagnostic_message(line));
for (index, line) in diagnostic.message.lines().enumerate() {
let line = match &diagnostic.source {
Some(source) if index == 0 => {
let source_highlight = Vec::from_iter(0..source.len());
highlight_diagnostic_message(source_highlight, &format!("{source}: {line}"))
}
_ => highlight_diagnostic_message(Vec::new(), line),
};
highlighted_lines.push(line);
}
Arc::new(move |cx: &mut BlockContext| {
@ -7519,11 +7564,14 @@ pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> Rend
})
}
pub fn highlight_diagnostic_message(message: &str) -> (String, Vec<usize>) {
pub fn highlight_diagnostic_message(
inital_highlights: Vec<usize>,
message: &str,
) -> (String, Vec<usize>) {
let mut message_without_backticks = String::new();
let mut prev_offset = 0;
let mut inside_block = false;
let mut highlights = Vec::new();
let mut highlights = inital_highlights;
for (match_ix, (offset, _)) in message
.match_indices('`')
.chain([(message.len(), "")])

View file

@ -211,10 +211,13 @@ impl EditorElement {
enum GutterHandlers {}
scene.push_mouse_region(
MouseRegion::new::<GutterHandlers>(cx.view_id(), cx.view_id() + 1, gutter_bounds)
.on_hover(|hover, _: &mut Editor, cx| {
cx.dispatch_action(GutterHover {
hovered: hover.started,
})
.on_hover(|hover, editor: &mut Editor, cx| {
editor.gutter_hover(
&GutterHover {
hovered: hover.started,
},
cx,
);
}),
)
}
@ -309,25 +312,17 @@ impl EditorElement {
editor.select(SelectPhase::End, cx);
}
if let Some(workspace) = editor
.workspace
.as_ref()
.and_then(|(workspace, _)| workspace.upgrade(cx))
{
if !pending_nonempty_selections && cmd && text_bounds.contains_point(position) {
let (point, target_point) = position_map.point_for_position(text_bounds, position);
if !pending_nonempty_selections && cmd && text_bounds.contains_point(position) {
let (point, target_point) = position_map.point_for_position(text_bounds, position);
if point == target_point {
workspace.update(cx, |workspace, cx| {
if shift {
go_to_fetched_type_definition(workspace, point, cx);
} else {
go_to_fetched_definition(workspace, point, cx);
}
});
return true;
if point == target_point {
if shift {
go_to_fetched_type_definition(editor, point, cx);
} else {
go_to_fetched_definition(editor, point, cx);
}
return true;
}
}
@ -762,8 +757,8 @@ impl EditorElement {
scene.push_mouse_region(
MouseRegion::new::<FoldMarkers>(cx.view_id(), *id as usize, bound)
.on_click(MouseButton::Left, move |_, _: &mut Editor, cx| {
cx.dispatch_action(UnfoldAt { buffer_row })
.on_click(MouseButton::Left, move |_, editor: &mut Editor, cx| {
editor.unfold_at(&UnfoldAt { buffer_row }, cx)
})
.with_notify_on_hover(true)
.with_notify_on_click(true),

View file

@ -1,3 +1,7 @@
use crate::{
display_map::ToDisplayPoint, Anchor, AnchorRangeExt, DisplayPoint, Editor, EditorSnapshot,
EditorStyle, RangeToAnchorExt,
};
use futures::FutureExt;
use gpui::{
actions,
@ -12,11 +16,6 @@ use settings::Settings;
use std::{ops::Range, sync::Arc, time::Duration};
use util::TryFutureExt;
use crate::{
display_map::ToDisplayPoint, Anchor, AnchorRangeExt, DisplayPoint, Editor, EditorSnapshot,
EditorStyle, GoToDiagnostic, RangeToAnchorExt,
};
pub const HOVER_DELAY_MILLIS: u64 = 350;
pub const HOVER_REQUEST_DELAY_MILLIS: u64 = 200;
@ -668,8 +667,8 @@ impl DiagnosticPopover {
..Default::default()
})
.on_move(|_, _, _| {}) // Consume move events so they don't reach regions underneath.
.on_click(MouseButton::Left, |_, _, cx| {
cx.dispatch_action(GoToDiagnostic)
.on_click(MouseButton::Left, |_, this, cx| {
this.go_to_diagnostic(&Default::default(), cx)
})
.with_cursor_style(CursorStyle::PointingHand)
.with_tooltip::<PrimaryDiagnostic>(

View file

@ -636,7 +636,7 @@ impl Item for Editor {
project: ModelHandle<Project>,
cx: &mut ViewContext<Self>,
) -> Task<Result<()>> {
self.report_event("save editor", cx);
self.report_editor_event("save", cx);
let format = self.perform_format(project.clone(), FormatTrigger::Save, cx);
let buffers = self.buffer().clone().read(cx).all_buffers();
cx.spawn(|_, mut cx| async move {

View file

@ -1,15 +1,11 @@
use std::ops::Range;
use crate::{Anchor, DisplayPoint, Editor, EditorSnapshot, SelectPhase};
use gpui::{Task, ViewContext};
use language::{Bias, ToOffset};
use project::LocationLink;
use settings::Settings;
use util::TryFutureExt;
use workspace::Workspace;
use crate::{
Anchor, DisplayPoint, Editor, EditorSnapshot, GoToDefinition, GoToTypeDefinition, SelectPhase,
};
#[derive(Debug, Default)]
pub struct LinkGoToDefinitionState {
@ -250,70 +246,51 @@ pub fn hide_link_definition(editor: &mut Editor, cx: &mut ViewContext<Editor>) {
}
pub fn go_to_fetched_definition(
workspace: &mut Workspace,
editor: &mut Editor,
point: DisplayPoint,
cx: &mut ViewContext<Workspace>,
cx: &mut ViewContext<Editor>,
) {
go_to_fetched_definition_of_kind(LinkDefinitionKind::Symbol, workspace, point, cx);
go_to_fetched_definition_of_kind(LinkDefinitionKind::Symbol, editor, point, cx);
}
pub fn go_to_fetched_type_definition(
workspace: &mut Workspace,
editor: &mut Editor,
point: DisplayPoint,
cx: &mut ViewContext<Workspace>,
cx: &mut ViewContext<Editor>,
) {
go_to_fetched_definition_of_kind(LinkDefinitionKind::Type, workspace, point, cx);
go_to_fetched_definition_of_kind(LinkDefinitionKind::Type, editor, point, cx);
}
fn go_to_fetched_definition_of_kind(
kind: LinkDefinitionKind,
workspace: &mut Workspace,
editor: &mut Editor,
point: DisplayPoint,
cx: &mut ViewContext<Workspace>,
cx: &mut ViewContext<Editor>,
) {
let active_item = workspace.active_item(cx);
let editor_handle = if let Some(editor) = active_item
.as_ref()
.and_then(|item| item.act_as::<Editor>(cx))
{
editor
} else {
return;
};
let (cached_definitions, cached_definitions_kind) = editor_handle.update(cx, |editor, cx| {
let definitions = editor.link_go_to_definition_state.definitions.clone();
hide_link_definition(editor, cx);
(definitions, editor.link_go_to_definition_state.kind)
});
let cached_definitions = editor.link_go_to_definition_state.definitions.clone();
hide_link_definition(editor, cx);
let cached_definitions_kind = editor.link_go_to_definition_state.kind;
let is_correct_kind = cached_definitions_kind == Some(kind);
if !cached_definitions.is_empty() && is_correct_kind {
editor_handle.update(cx, |editor, cx| {
if !editor.focused {
cx.focus_self();
}
});
if !editor.focused {
cx.focus_self();
}
Editor::navigate_to_definitions(workspace, editor_handle, cached_definitions, cx);
editor.navigate_to_definitions(cached_definitions, cx);
} else {
editor_handle.update(cx, |editor, cx| {
editor.select(
SelectPhase::Begin {
position: point,
add: false,
click_count: 1,
},
cx,
);
});
editor.select(
SelectPhase::Begin {
position: point,
add: false,
click_count: 1,
},
cx,
);
match kind {
LinkDefinitionKind::Symbol => Editor::go_to_definition(workspace, &GoToDefinition, cx),
LinkDefinitionKind::Type => {
Editor::go_to_type_definition(workspace, &GoToTypeDefinition, cx)
}
LinkDefinitionKind::Symbol => editor.go_to_definition(&Default::default(), cx),
LinkDefinitionKind::Type => editor.go_to_type_definition(&Default::default(), cx),
}
}
}
@ -426,8 +403,8 @@ mod tests {
])))
});
cx.update_workspace(|workspace, cx| {
go_to_fetched_type_definition(workspace, hover_point, cx);
cx.update_editor(|editor, cx| {
go_to_fetched_type_definition(editor, hover_point, cx);
});
requests.next().await;
cx.foreground().run_until_parked();
@ -635,8 +612,8 @@ mod tests {
"});
// Cmd click with existing definition doesn't re-request and dismisses highlight
cx.update_workspace(|workspace, cx| {
go_to_fetched_definition(workspace, hover_point, cx);
cx.update_editor(|editor, cx| {
go_to_fetched_definition(editor, hover_point, cx);
});
// Assert selection moved to to definition
cx.lsp
@ -676,8 +653,8 @@ mod tests {
},
])))
});
cx.update_workspace(|workspace, cx| {
go_to_fetched_definition(workspace, hover_point, cx);
cx.update_editor(|editor, cx| {
go_to_fetched_definition(editor, hover_point, cx);
});
requests.next().await;
cx.foreground().run_until_parked();