Skip to main content

gpui_base/input/editor/
language.rs

1use std::{cell::RefCell, rc::Rc};
2
3use super::{LanguageConfig, Rope, SyntaxContext, SyntaxContextProvider};
4use gpui::{App, Global, SharedString};
5
6/// Supplies language identities, editing defaults, and syntax providers to Base.
7///
8/// Implementations normalize aliases consistently with their highlighter. Syntax
9/// providers belong to individual editors; configuration values can be shared.
10/// Base does not require a parser. Component installs its implementation at init.
11pub trait LanguageProvider {
12    /// Resolve a name or alias to its canonical identifier. Resolving an
13    /// already canonical identifier must return the same identifier.
14    fn language_name(&self, name: &str) -> SharedString {
15        name.to_lowercase().into()
16    }
17
18    /// Editing defaults for a canonical identifier; application registrations
19    /// take precedence over these defaults.
20    fn config(&self, _name: &str) -> Rc<LanguageConfig> {
21        Rc::new(LanguageConfig::default())
22    }
23
24    /// Creates an editor-owned provider, cached until the language or service
25    /// changes. After changing grammar registrations, reselect the editor's
26    /// language with `set_highlighter` to replace its cached provider.
27    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    // Registration order preserves precedence when a replacement service resolves aliases.
43    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
68/// Install the application's language service. Existing editors use the new
69/// service on their next editing operation, without waiting for a render.
70/// Registered configurations are retained and resolved through the new service.
71pub fn set_language_provider(provider: Rc<dyn LanguageProvider>, cx: &mut App) {
72    Languages::global(cx).0.borrow_mut().provider = provider;
73}
74
75/// Replace a language's editing configuration for this application.
76/// Existing editors read the replacement on their next edit. Aliases follow the
77/// installed language provider; Base alone treats names case-insensitively.
78/// This does not change `auto_close` or `smart_indent` preferences.
79pub 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/// One editor's language selection. Configurations are read from shared settings;
95/// only the syntax provider is retained, because it owns a document parse cache.
96#[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}