mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-18 18:08:07 +03:00
Fix panic when evaluating a code snippet containing multi-byte characters (#14269)
Also, don't retrieve code snippets when rendering the repl quick action button Release Notes: - N/A --------- Co-authored-by: Kyle Kelley <kylek@zed.dev> Co-authored-by: Kyle Kelley <rgbkrk@gmail.com>
This commit is contained in:
parent
906688f012
commit
ac528dda64
@ -11,7 +11,8 @@ use gpui::{
|
|||||||
actions, prelude::*, AppContext, AsyncWindowContext, EntityId, EventEmitter, FocusHandle,
|
actions, prelude::*, AppContext, AsyncWindowContext, EntityId, EventEmitter, FocusHandle,
|
||||||
FocusOutEvent, FocusableView, Subscription, Task, View, WeakView,
|
FocusOutEvent, FocusableView, Subscription, Task, View, WeakView,
|
||||||
};
|
};
|
||||||
use language::Point;
|
use language::{Language, Point};
|
||||||
|
use multi_buffer::MultiBufferRow;
|
||||||
use project::Fs;
|
use project::Fs;
|
||||||
use settings::{Settings as _, SettingsStore};
|
use settings::{Settings as _, SettingsStore};
|
||||||
use std::{ops::Range, sync::Arc};
|
use std::{ops::Range, sync::Arc};
|
||||||
@ -174,34 +175,14 @@ impl RuntimePanel {
|
|||||||
let range = if selection.is_empty() {
|
let range = if selection.is_empty() {
|
||||||
let cursor = selection.head();
|
let cursor = selection.head();
|
||||||
|
|
||||||
let line_start = multi_buffer_snapshot.offset_to_point(cursor).row;
|
let cursor_row = multi_buffer_snapshot.offset_to_point(cursor).row;
|
||||||
let mut start_offset = multi_buffer_snapshot.point_to_offset(Point::new(line_start, 0));
|
let start_offset = multi_buffer_snapshot.point_to_offset(Point::new(cursor_row, 0));
|
||||||
|
|
||||||
// Iterate backwards to find the start of the line
|
let end_point = Point::new(
|
||||||
while start_offset > 0 {
|
cursor_row,
|
||||||
let ch = multi_buffer_snapshot
|
multi_buffer_snapshot.line_len(MultiBufferRow(cursor_row)),
|
||||||
.chars_at(start_offset - 1)
|
);
|
||||||
.next()
|
let end_offset = start_offset.saturating_add(end_point.column as usize);
|
||||||
.unwrap_or('\0');
|
|
||||||
if ch == '\n' {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
start_offset -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut end_offset = cursor;
|
|
||||||
|
|
||||||
// Iterate forwards to find the end of the line
|
|
||||||
while end_offset < multi_buffer_snapshot.len() {
|
|
||||||
let ch = multi_buffer_snapshot
|
|
||||||
.chars_at(end_offset)
|
|
||||||
.next()
|
|
||||||
.unwrap_or('\0');
|
|
||||||
if ch == '\n' {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
end_offset += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a range from the start to the end of the line
|
// Create a range from the start to the end of the line
|
||||||
start_offset..end_offset
|
start_offset..end_offset
|
||||||
@ -216,7 +197,7 @@ impl RuntimePanel {
|
|||||||
&self,
|
&self,
|
||||||
editor: WeakView<Editor>,
|
editor: WeakView<Editor>,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) -> Option<(String, Arc<str>, Range<Anchor>)> {
|
) -> Option<(String, Arc<Language>, Range<Anchor>)> {
|
||||||
let editor = editor.upgrade()?;
|
let editor = editor.upgrade()?;
|
||||||
|
|
||||||
let buffer = editor.read(cx).buffer().read(cx).snapshot(cx);
|
let buffer = editor.read(cx).buffer().read(cx).snapshot(cx);
|
||||||
@ -226,30 +207,24 @@ impl RuntimePanel {
|
|||||||
.text_for_range(anchor_range.clone())
|
.text_for_range(anchor_range.clone())
|
||||||
.collect::<String>();
|
.collect::<String>();
|
||||||
|
|
||||||
let start_language = buffer.language_at(anchor_range.start);
|
let start_language = buffer.language_at(anchor_range.start)?;
|
||||||
let end_language = buffer.language_at(anchor_range.end);
|
let end_language = buffer.language_at(anchor_range.end)?;
|
||||||
|
if start_language != end_language {
|
||||||
let language_name = if start_language == end_language {
|
|
||||||
start_language
|
|
||||||
.map(|language| language.code_fence_block_name())
|
|
||||||
.filter(|lang| **lang != *"markdown")?
|
|
||||||
} else {
|
|
||||||
// If the selection spans multiple languages, don't run it
|
|
||||||
return None;
|
return None;
|
||||||
};
|
}
|
||||||
|
|
||||||
Some((selected_text, language_name, anchor_range))
|
Some((selected_text, start_language.clone(), anchor_range))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn language(
|
pub fn language(
|
||||||
&self,
|
&self,
|
||||||
editor: WeakView<Editor>,
|
editor: WeakView<Editor>,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) -> Option<Arc<str>> {
|
) -> Option<Arc<Language>> {
|
||||||
match self.snippet(editor, cx) {
|
let editor = editor.upgrade()?;
|
||||||
Some((_, language, _)) => Some(language),
|
let selection = editor.read(cx).selections.newest::<usize>(cx);
|
||||||
None => None,
|
let buffer = editor.read(cx).buffer().read(cx).snapshot(cx);
|
||||||
}
|
buffer.language_at(selection.head()).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn refresh_kernelspecs(&mut self, cx: &mut ViewContext<Self>) -> Task<anyhow::Result<()>> {
|
pub fn refresh_kernelspecs(&mut self, cx: &mut ViewContext<Self>) -> Task<anyhow::Result<()>> {
|
||||||
@ -266,11 +241,12 @@ impl RuntimePanel {
|
|||||||
|
|
||||||
pub fn kernelspec(
|
pub fn kernelspec(
|
||||||
&self,
|
&self,
|
||||||
language_name: &str,
|
language: &Language,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) -> Option<KernelSpecification> {
|
) -> Option<KernelSpecification> {
|
||||||
let settings = JupyterSettings::get_global(cx);
|
let settings = JupyterSettings::get_global(cx);
|
||||||
let selected_kernel = settings.kernel_selections.get(language_name);
|
let language_name = language.code_fence_block_name();
|
||||||
|
let selected_kernel = settings.kernel_selections.get(language_name.as_ref());
|
||||||
|
|
||||||
self.kernel_specifications
|
self.kernel_specifications
|
||||||
.iter()
|
.iter()
|
||||||
@ -296,7 +272,7 @@ impl RuntimePanel {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let (selected_text, language_name, anchor_range) = match self.snippet(editor.clone(), cx) {
|
let (selected_text, language, anchor_range) = match self.snippet(editor.clone(), cx) {
|
||||||
Some(snippet) => snippet,
|
Some(snippet) => snippet,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
@ -304,8 +280,8 @@ impl RuntimePanel {
|
|||||||
let entity_id = editor.entity_id();
|
let entity_id = editor.entity_id();
|
||||||
|
|
||||||
let kernel_specification = self
|
let kernel_specification = self
|
||||||
.kernelspec(&language_name, cx)
|
.kernelspec(&language, cx)
|
||||||
.with_context(|| format!("No kernel found for language: {language_name}"))?;
|
.with_context(|| format!("No kernel found for language: {}", language.name()))?;
|
||||||
|
|
||||||
let session = self.sessions.entry(entity_id).or_insert_with(|| {
|
let session = self.sessions.entry(entity_id).or_insert_with(|| {
|
||||||
let view =
|
let view =
|
||||||
@ -320,7 +296,6 @@ impl RuntimePanel {
|
|||||||
panel.sessions.remove(&shutdown_event.entity_id());
|
panel.sessions.remove(&shutdown_event.entity_id());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -350,7 +325,7 @@ impl RuntimePanel {
|
|||||||
pub enum SessionSupport {
|
pub enum SessionSupport {
|
||||||
ActiveSession(View<Session>),
|
ActiveSession(View<Session>),
|
||||||
Inactive(KernelSpecification),
|
Inactive(KernelSpecification),
|
||||||
RequiresSetup(String),
|
RequiresSetup(Arc<str>),
|
||||||
Unsupported,
|
Unsupported,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,11 +352,12 @@ impl RuntimePanel {
|
|||||||
match kernelspec {
|
match kernelspec {
|
||||||
Some(kernelspec) => SessionSupport::Inactive(kernelspec),
|
Some(kernelspec) => SessionSupport::Inactive(kernelspec),
|
||||||
None => {
|
None => {
|
||||||
let language: String = language.to_lowercase();
|
// If no kernelspec but language is one of typescript or python
|
||||||
// If no kernelspec but language is one of typescript, python, r, or julia
|
|
||||||
// then we return RequiresSetup
|
// then we return RequiresSetup
|
||||||
match language.as_str() {
|
match language.name().as_ref() {
|
||||||
"typescript" | "python" => SessionSupport::RequiresSetup(language),
|
"TypeScript" | "Python" => {
|
||||||
|
SessionSupport::RequiresSetup(language.name())
|
||||||
|
}
|
||||||
_ => SessionSupport::Unsupported,
|
_ => SessionSupport::Unsupported,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user