example: Fix lint performance in CodeEditor example. (#1259)
Move AutoCorrect lint to background.
This commit is contained in:
parent
8a3ef51ea1
commit
3fe9bc8de0
1 changed files with 108 additions and 57 deletions
|
|
@ -1,4 +1,10 @@
|
||||||
use std::{cell::RefCell, ops::Range, rc::Rc, str::FromStr, sync::Arc, time::Duration};
|
use std::{
|
||||||
|
ops::Range,
|
||||||
|
rc::Rc,
|
||||||
|
str::FromStr,
|
||||||
|
sync::{Arc, RwLock},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
use anyhow::Ok;
|
use anyhow::Ok;
|
||||||
use gpui::{prelude::FluentBuilder, *};
|
use gpui::{prelude::FluentBuilder, *};
|
||||||
|
|
@ -43,6 +49,7 @@ pub struct Example {
|
||||||
soft_wrap: bool,
|
soft_wrap: bool,
|
||||||
lsp_store: ExampleLspStore,
|
lsp_store: ExampleLspStore,
|
||||||
_subscriptions: Vec<Subscription>,
|
_subscriptions: Vec<Subscription>,
|
||||||
|
_lint_task: Task<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
|
@ -111,7 +118,9 @@ const LANGUAGES: [(Lang, &'static str); 12] = [
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ExampleLspStore {
|
pub struct ExampleLspStore {
|
||||||
completions: Arc<Vec<CompletionItem>>,
|
completions: Arc<Vec<CompletionItem>>,
|
||||||
code_actions: Rc<RefCell<Vec<(Range<usize>, CodeAction)>>>,
|
code_actions: Arc<RwLock<Vec<(Range<usize>, CodeAction)>>>,
|
||||||
|
diagnostics: Arc<RwLock<Vec<Diagnostic>>>,
|
||||||
|
dirty: Arc<RwLock<bool>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExampleLspStore {
|
impl ExampleLspStore {
|
||||||
|
|
@ -123,9 +132,38 @@ impl ExampleLspStore {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
completions: Arc::new(completions),
|
completions: Arc::new(completions),
|
||||||
code_actions: Rc::new(RefCell::new(vec![])),
|
code_actions: Arc::new(RwLock::new(vec![])),
|
||||||
|
diagnostics: Arc::new(RwLock::new(vec![])),
|
||||||
|
dirty: Arc::new(RwLock::new(false)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn diagnostics(&self) -> Vec<Diagnostic> {
|
||||||
|
let guard = self.diagnostics.read().unwrap();
|
||||||
|
guard.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_diagnostics(&self, diagnostics: Vec<Diagnostic>) {
|
||||||
|
let mut guard = self.diagnostics.write().unwrap();
|
||||||
|
*guard = diagnostics;
|
||||||
|
*self.dirty.write().unwrap() = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn code_actions(&self) -> Vec<(Range<usize>, CodeAction)> {
|
||||||
|
let guard = self.code_actions.read().unwrap();
|
||||||
|
guard.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_code_actions(&self, code_actions: Vec<(Range<usize>, CodeAction)>) {
|
||||||
|
let mut guard = self.code_actions.write().unwrap();
|
||||||
|
*guard = code_actions;
|
||||||
|
*self.dirty.write().unwrap() = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_dirty(&self) -> bool {
|
||||||
|
let guard = self.dirty.read().unwrap();
|
||||||
|
*guard
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompletionProvider for ExampleLspStore {
|
impl CompletionProvider for ExampleLspStore {
|
||||||
|
|
@ -146,7 +184,7 @@ impl CompletionProvider for ExampleLspStore {
|
||||||
|
|
||||||
// Simulate to delay for fetching completions
|
// Simulate to delay for fetching completions
|
||||||
let items = self.completions.clone();
|
let items = self.completions.clone();
|
||||||
cx.background_executor().spawn(async move {
|
cx.background_spawn(async move {
|
||||||
// Simulate a slow completion source, to test Editor async handling.
|
// Simulate a slow completion source, to test Editor async handling.
|
||||||
smol::Timer::after(Duration::from_millis(20)).await;
|
smol::Timer::after(Duration::from_millis(20)).await;
|
||||||
|
|
||||||
|
|
@ -186,7 +224,7 @@ impl CodeActionProvider for ExampleLspStore {
|
||||||
_cx: &mut App,
|
_cx: &mut App,
|
||||||
) -> Task<Result<Vec<CodeAction>>> {
|
) -> Task<Result<Vec<CodeAction>>> {
|
||||||
let mut actions = vec![];
|
let mut actions = vec![];
|
||||||
for (node_range, code_action) in self.code_actions.borrow().iter() {
|
for (node_range, code_action) in self.code_actions().iter() {
|
||||||
if !(range.start >= node_range.start && range.end <= node_range.end) {
|
if !(range.start >= node_range.start && range.end <= node_range.end) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -498,6 +536,7 @@ impl Example {
|
||||||
soft_wrap: false,
|
soft_wrap: false,
|
||||||
lsp_store,
|
lsp_store,
|
||||||
_subscriptions,
|
_subscriptions,
|
||||||
|
_lint_task: Task::ready(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -572,16 +611,18 @@ impl Example {
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lint_document(&self, cx: &mut Context<Self>) {
|
fn lint_document(&mut self, cx: &mut Context<Self>) {
|
||||||
// Subscribe to input changes and perform linting with AutoCorrect for markers example.
|
let language = self.language.name().to_string();
|
||||||
let value = self.editor.read(cx).value().clone();
|
let lsp_store = self.lsp_store.clone();
|
||||||
let result = autocorrect::lint_for(value.as_str(), self.language.name());
|
let text = self.editor.read(cx).text().clone();
|
||||||
|
|
||||||
|
self._lint_task = cx.background_spawn(async move {
|
||||||
|
let value = text.to_string();
|
||||||
|
let result = autocorrect::lint_for(value.as_str(), &language);
|
||||||
|
|
||||||
let mut code_actions = vec![];
|
let mut code_actions = vec![];
|
||||||
self.editor.update(cx, |state, cx| {
|
let mut diagnostics = vec![];
|
||||||
let text = state.text().clone();
|
|
||||||
state.diagnostics_mut().map(|diagnostics| {
|
|
||||||
diagnostics.clear();
|
|
||||||
for item in result.lines.iter() {
|
for item in result.lines.iter() {
|
||||||
let severity = match item.severity {
|
let severity = match item.severity {
|
||||||
autocorrect::Severity::Error => DiagnosticSeverity::Warning,
|
autocorrect::Severity::Error => DiagnosticSeverity::Warning,
|
||||||
|
|
@ -625,12 +666,10 @@ impl Example {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
self.lsp_store.code_actions.replace(code_actions.clone());
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
cx.notify();
|
lsp_store.update_code_actions(code_actions.clone());
|
||||||
|
lsp_store.update_diagnostics(diagnostics.clone());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -639,6 +678,18 @@ impl Render for Example {
|
||||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
self.update_highlighter(window, cx);
|
self.update_highlighter(window, cx);
|
||||||
|
|
||||||
|
// Update diagnostics
|
||||||
|
if self.lsp_store.is_dirty() {
|
||||||
|
let diagnostics = self.lsp_store.diagnostics();
|
||||||
|
self.editor.update(cx, |state, cx| {
|
||||||
|
state.diagnostics_mut().map(|set| {
|
||||||
|
set.clear();
|
||||||
|
set.extend(diagnostics);
|
||||||
|
});
|
||||||
|
cx.notify();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
v_flex().size_full().child(
|
v_flex().size_full().child(
|
||||||
v_flex()
|
v_flex()
|
||||||
.id("source")
|
.id("source")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue