gpui_base/input/editor/
language.rs1use std::{cell::RefCell, rc::Rc};
2
3use super::{LanguageConfig, Rope, SyntaxContext, SyntaxContextProvider};
4use gpui::{App, Global, SharedString};
5
6pub trait LanguageProvider {
12 fn language_name(&self, name: &str) -> SharedString {
15 name.to_lowercase().into()
16 }
17
18 fn config(&self, _name: &str) -> Rc<LanguageConfig> {
21 Rc::new(LanguageConfig::default())
22 }
23
24 fn syntax_context_provider(&self, _name: &str) -> Option<Rc<dyn SyntaxContextProvider>> {
28 None
29 }
30}
31
32#[derive(Default)]
33struct DefaultLanguages(Rc<LanguageConfig>);
34impl LanguageProvider for DefaultLanguages {
35 fn config(&self, _: &str) -> Rc<LanguageConfig> {
36 self.0.clone()
37 }
38}
39
40struct LanguageSettings {
41 provider: Rc<dyn LanguageProvider>,
42 configs: Vec<(SharedString, Rc<LanguageConfig>)>,
44}
45
46impl Default for LanguageSettings {
47 fn default() -> Self {
48 Self {
49 provider: Rc::new(DefaultLanguages::default()),
50 configs: Vec::new(),
51 }
52 }
53}
54
55#[derive(Clone, Default)]
56struct Languages(Rc<RefCell<LanguageSettings>>);
57impl Global for Languages {}
58
59impl Languages {
60 fn global(cx: &mut App) -> Self {
61 if !cx.has_global::<Self>() {
62 cx.set_global(Self::default());
63 }
64 cx.global::<Self>().clone()
65 }
66}
67
68pub fn set_language_provider(provider: Rc<dyn LanguageProvider>, cx: &mut App) {
72 Languages::global(cx).0.borrow_mut().provider = provider;
73}
74
75pub fn set_language_config(language: impl AsRef<str>, config: LanguageConfig, cx: &mut App) {
80 let languages = Languages::global(cx);
81 let name: SharedString = language.as_ref().to_string().into();
82 let mut settings = languages.0.borrow_mut();
83 settings
84 .configs
85 .retain(|(registered, _)| *registered != name);
86 settings.configs.push((name, Rc::new(config)));
87}
88
89struct LanguageSyntax {
90 source: Rc<dyn LanguageProvider>,
91 provider: Option<Rc<dyn SyntaxContextProvider>>,
92}
93
94#[derive(Clone, Default)]
97pub(crate) struct EditorLanguage {
98 name: SharedString,
99 languages: Languages,
100 syntax: Rc<RefCell<Option<LanguageSyntax>>>,
101}
102
103impl EditorLanguage {
104 pub(crate) fn new(cx: &mut App) -> Self {
105 Self {
106 name: SharedString::default(),
107 languages: Languages::global(cx),
108 syntax: Rc::default(),
109 }
110 }
111
112 pub(crate) fn name(&self) -> SharedString {
113 self.name.clone()
114 }
115
116 pub(crate) fn set_name(&mut self, name: SharedString) {
117 self.name = name;
118 self.syntax = Rc::new(RefCell::new(None));
119 }
120
121 pub(crate) fn config(&self) -> Rc<LanguageConfig> {
122 let source = self.languages.0.borrow().provider.clone();
123 let name = source.language_name(&self.name);
124 let configured = self
125 .languages
126 .0
127 .borrow()
128 .configs
129 .iter()
130 .rev()
131 .find(|(registered, _)| source.language_name(registered) == name)
132 .map(|(_, config)| config.clone());
133 configured.unwrap_or_else(|| source.config(&name))
134 }
135
136 pub(crate) fn context_at(&self, text: &Rope, offset: usize) -> SyntaxContext {
137 let source = self.languages.0.borrow().provider.clone();
138 let mut syntax = self.syntax.borrow_mut();
139 if syntax
140 .as_ref()
141 .is_none_or(|cached| !Rc::ptr_eq(&cached.source, &source))
142 {
143 let name = source.language_name(&self.name);
144 *syntax = Some(LanguageSyntax {
145 provider: source.syntax_context_provider(&name),
146 source,
147 });
148 }
149 let provider = syntax.as_ref().and_then(|syntax| syntax.provider.clone());
150 drop(syntax);
151 provider.map_or(SyntaxContext::Code, |provider| {
152 provider.context_at(text, offset)
153 })
154 }
155}