on master help sign in
Add runtime language configuration (#1794) (#1866)

* Add runtime language configuration (#1794) * Add set-language typable command to change the language of current buffer. * Add completer for available language options. * Update set-language to refresh language server as well * Add language id based config lookup on `syntax::Loader`. * Add `Document::set_language3` to set programming language based on language id. * Update `Editor::refresh_language_server` to try language detection only if language is not already set. * Remove language detection from Editor::refresh_language_server * Move document language detection to where the scratch buffer is saved. * Rename Document::set_language3 to Document::set_language_by_language_id. * Remove unnecessary clone in completers::language

commitd962e06e91b997813092cc5e49a800cc9d4f0ee1 authorRoland Kovacs <zen3ger@tutanota.com> dateTue 5 Apr 2022, 02:56 (5 years ago) parent6fc6f87
6 files changed+70−1
book/src/generated/typable-cmd.md+1 helix-core/src/syntax.rs+11 helix-term/src/commands/typed.rs+26 helix-term/src/ui/mod.rs+21 helix-view/src/document.rs+11 helix-view/src/editor.rs−1
book/src/generated/typable-cmd.md+1
@@ -53,6 +53,7 @@
5353| `:hsplit-new`, `:hnew` | Open a scratch buffer in a horizontal split. |
5454| `:tutor` | Open the tutorial. |
5555| `:goto`, `:g` | Go to line number. |
56+| `:set-language`, `:lang` | Set the language of current buffer. |
5657| `:set-option`, `:set` | Set a config option at runtime |
5758| `:sort` | Sort ranges in selection. |
5859| `:rsort` | Sort ranges in selection in reverse order. |
helix-core/src/syntax.rs+11
@@ -504,6 +504,13 @@ impl Loader {
504504 .cloned()
505505 }
506506
507+ pub fn language_config_for_language_id(&self, id: &str) -> Option<Arc<LanguageConfiguration>> {
508+ self.language_configs
509+ .iter()
510+ .find(|config| config.language_id == id)
511+ .cloned()
512+ }
513+
507514 pub fn language_configuration_for_injection_string(
508515 &self,
509516 string: &str,
@@ -529,6 +536,10 @@ impl Loader {
529536 None
530537 }
531538
539+ pub fn language_configs(&self) -> impl Iterator<Item = &Arc<LanguageConfiguration>> {
540+ self.language_configs.iter()
541+ }
542+
532543 pub fn set_scopes(&self, scopes: Vec<String>) {
533544 self.scopes.store(Arc::new(scopes));
534545
helix-term/src/commands/typed.rs+26
@@ -217,6 +217,7 @@ fn write_impl(cx: &mut compositor::Context, path: Option<&Cow<str>>) -> anyhow::
217217
218218 if path.is_some() {
219219 let id = doc.id();
220+ doc.detect_language(cx.editor.syn_loader.clone());
220221 let _ = cx.editor.refresh_language_server(id);
221222 }
222223 Ok(())
@@ -931,6 +932,24 @@ fn setting(
931932 Ok(())
932933}
933934
935+/// Change the language of the current buffer at runtime.
936+fn language(
937+ cx: &mut compositor::Context,
938+ args: &[Cow<str>],
939+ _event: PromptEvent,
940+) -> anyhow::Result<()> {
941+ if args.len() != 1 {
942+ anyhow::bail!("Bad arguments. Usage: `:set-language language`");
943+ }
944+
945+ let doc = doc_mut!(cx.editor);
946+ doc.set_language_by_language_id(&args[0], cx.editor.syn_loader.clone());
947+
948+ let id = doc.id();
949+ cx.editor.refresh_language_server(id);
950+ Ok(())
951+}
952+
934953fn sort(
935954 cx: &mut compositor::Context,
936955 args: &[Cow<str>],
@@ -1408,6 +1427,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
14081427 fun: goto_line_number,
14091428 completer: None,
14101429 },
1430+ TypableCommand {
1431+ name: "set-language",
1432+ aliases: &["lang"],
1433+ doc: "Set the language of current buffer.",
1434+ fun: language,
1435+ completer: Some(completers::language),
1436+ },
14111437 TypableCommand {
14121438 name: "set-option",
14131439 aliases: &["set"],
helix-term/src/ui/mod.rs+21
@@ -298,6 +298,27 @@ pub mod completers {
298298 })
299299 }
300300
301+ pub fn language(editor: &Editor, input: &str) -> Vec<Completion> {
302+ let matcher = Matcher::default();
303+
304+ let mut matches: Vec<_> = editor
305+ .syn_loader
306+ .language_configs()
307+ .filter_map(|config| {
308+ matcher
309+ .fuzzy_match(&config.language_id, input)
310+ .map(|score| (&config.language_id, score))
311+ })
312+ .collect();
313+
314+ matches.sort_unstable_by_key(|(_language, score)| Reverse(*score));
315+
316+ matches
317+ .into_iter()
318+ .map(|(language, _score)| ((0..), language.clone().into()))
319+ .collect()
320+ }
321+
301322 pub fn directory(_editor: &Editor, input: &str) -> Vec<Completion> {
302323 filename_impl(input, |entry| {
303324 let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir());
helix-view/src/document.rs+11
@@ -607,6 +607,17 @@ impl Document {
607607 self.set_language(language_config, Some(config_loader));
608608 }
609609
610+ /// Set the programming language for the file if you know the language but don't have the
611+ /// [`syntax::LanguageConfiguration`] for it.
612+ pub fn set_language_by_language_id(
613+ &mut self,
614+ language_id: &str,
615+ config_loader: Arc<syntax::Loader>,
616+ ) {
617+ let language_config = config_loader.language_config_for_language_id(language_id);
618+ self.set_language(language_config, Some(config_loader));
619+ }
620+
610621 /// Set the LSP.
611622 pub fn set_language_server(&mut self, language_server: Option<Arc<helix_lsp::Client>>) {
612623 self.language_server = language_server;
helix-view/src/editor.rs−1
@@ -448,7 +448,6 @@ impl Editor {
448448 /// Refreshes the language server for a given document
449449 pub fn refresh_language_server(&mut self, doc_id: DocumentId) -> Option<()> {
450450 let doc = self.documents.get_mut(&doc_id)?;
451− doc.detect_language(self.syn_loader.clone());
452451 Self::launch_language_server(&mut self.language_servers, doc)
453452 }
454453