mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-07 20:39:04 +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,
|
||||
FocusOutEvent, FocusableView, Subscription, Task, View, WeakView,
|
||||
};
|
||||
use language::Point;
|
||||
use language::{Language, Point};
|
||||
use multi_buffer::MultiBufferRow;
|
||||
use project::Fs;
|
||||
use settings::{Settings as _, SettingsStore};
|
||||
use std::{ops::Range, sync::Arc};
|
||||
@ -174,34 +175,14 @@ impl RuntimePanel {
|
||||
let range = if selection.is_empty() {
|
||||
let cursor = selection.head();
|
||||
|
||||
let line_start = multi_buffer_snapshot.offset_to_point(cursor).row;
|
||||
let mut start_offset = multi_buffer_snapshot.point_to_offset(Point::new(line_start, 0));
|
||||
let cursor_row = multi_buffer_snapshot.offset_to_point(cursor).row;
|
||||
let start_offset = multi_buffer_snapshot.point_to_offset(Point::new(cursor_row, 0));
|
||||
|
||||
// Iterate backwards to find the start of the line
|
||||
while start_offset > 0 {
|
||||
let ch = multi_buffer_snapshot
|
||||
.chars_at(start_offset - 1)
|
||||
.next()
|
||||
.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;
|
||||
}
|
||||
let end_point = Point::new(
|
||||
cursor_row,
|
||||
multi_buffer_snapshot.line_len(MultiBufferRow(cursor_row)),
|
||||
);
|
||||
let end_offset = start_offset.saturating_add(end_point.column as usize);
|
||||
|
||||
// Create a range from the start to the end of the line
|
||||
start_offset..end_offset
|
||||
@ -216,7 +197,7 @@ impl RuntimePanel {
|
||||
&self,
|
||||
editor: WeakView<Editor>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Option<(String, Arc<str>, Range<Anchor>)> {
|
||||
) -> Option<(String, Arc<Language>, Range<Anchor>)> {
|
||||
let editor = editor.upgrade()?;
|
||||
|
||||
let buffer = editor.read(cx).buffer().read(cx).snapshot(cx);
|
||||
@ -226,30 +207,24 @@ impl RuntimePanel {
|
||||
.text_for_range(anchor_range.clone())
|
||||
.collect::<String>();
|
||||
|
||||
let start_language = buffer.language_at(anchor_range.start);
|
||||
let end_language = buffer.language_at(anchor_range.end);
|
||||
|
||||
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
|
||||
let start_language = buffer.language_at(anchor_range.start)?;
|
||||
let end_language = buffer.language_at(anchor_range.end)?;
|
||||
if start_language != end_language {
|
||||
return None;
|
||||
};
|
||||
}
|
||||
|
||||
Some((selected_text, language_name, anchor_range))
|
||||
Some((selected_text, start_language.clone(), anchor_range))
|
||||
}
|
||||
|
||||
pub fn language(
|
||||
&self,
|
||||
editor: WeakView<Editor>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Option<Arc<str>> {
|
||||
match self.snippet(editor, cx) {
|
||||
Some((_, language, _)) => Some(language),
|
||||
None => None,
|
||||
}
|
||||
) -> Option<Arc<Language>> {
|
||||
let editor = editor.upgrade()?;
|
||||
let selection = editor.read(cx).selections.newest::<usize>(cx);
|
||||
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<()>> {
|
||||
@ -266,11 +241,12 @@ impl RuntimePanel {
|
||||
|
||||
pub fn kernelspec(
|
||||
&self,
|
||||
language_name: &str,
|
||||
language: &Language,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Option<KernelSpecification> {
|
||||
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
|
||||
.iter()
|
||||
@ -296,7 +272,7 @@ impl RuntimePanel {
|
||||
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,
|
||||
None => return Ok(()),
|
||||
};
|
||||
@ -304,8 +280,8 @@ impl RuntimePanel {
|
||||
let entity_id = editor.entity_id();
|
||||
|
||||
let kernel_specification = self
|
||||
.kernelspec(&language_name, cx)
|
||||
.with_context(|| format!("No kernel found for language: {language_name}"))?;
|
||||
.kernelspec(&language, cx)
|
||||
.with_context(|| format!("No kernel found for language: {}", language.name()))?;
|
||||
|
||||
let session = self.sessions.entry(entity_id).or_insert_with(|| {
|
||||
let view =
|
||||
@ -320,7 +296,6 @@ impl RuntimePanel {
|
||||
panel.sessions.remove(&shutdown_event.entity_id());
|
||||
}
|
||||
}
|
||||
//
|
||||
},
|
||||
);
|
||||
|
||||
@ -350,7 +325,7 @@ impl RuntimePanel {
|
||||
pub enum SessionSupport {
|
||||
ActiveSession(View<Session>),
|
||||
Inactive(KernelSpecification),
|
||||
RequiresSetup(String),
|
||||
RequiresSetup(Arc<str>),
|
||||
Unsupported,
|
||||
}
|
||||
|
||||
@ -377,11 +352,12 @@ impl RuntimePanel {
|
||||
match kernelspec {
|
||||
Some(kernelspec) => SessionSupport::Inactive(kernelspec),
|
||||
None => {
|
||||
let language: String = language.to_lowercase();
|
||||
// If no kernelspec but language is one of typescript, python, r, or julia
|
||||
// If no kernelspec but language is one of typescript or python
|
||||
// then we return RequiresSetup
|
||||
match language.as_str() {
|
||||
"typescript" | "python" => SessionSupport::RequiresSetup(language),
|
||||
match language.name().as_ref() {
|
||||
"TypeScript" | "Python" => {
|
||||
SessionSupport::RequiresSetup(language.name())
|
||||
}
|
||||
_ => SessionSupport::Unsupported,
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user