mirror of https://github.com/helix-editor/helix
* 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::languagepull/1962/head
parent
6fc6f87260
commit
d962e06e91
|
@ -53,6 +53,7 @@
|
||||||
| `:hsplit-new`, `:hnew` | Open a scratch buffer in a horizontal split. |
|
| `:hsplit-new`, `:hnew` | Open a scratch buffer in a horizontal split. |
|
||||||
| `:tutor` | Open the tutorial. |
|
| `:tutor` | Open the tutorial. |
|
||||||
| `:goto`, `:g` | Go to line number. |
|
| `:goto`, `:g` | Go to line number. |
|
||||||
|
| `:set-language`, `:lang` | Set the language of current buffer. |
|
||||||
| `:set-option`, `:set` | Set a config option at runtime |
|
| `:set-option`, `:set` | Set a config option at runtime |
|
||||||
| `:sort` | Sort ranges in selection. |
|
| `:sort` | Sort ranges in selection. |
|
||||||
| `:rsort` | Sort ranges in selection in reverse order. |
|
| `:rsort` | Sort ranges in selection in reverse order. |
|
||||||
|
|
|
@ -504,6 +504,13 @@ impl Loader {
|
||||||
.cloned()
|
.cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn language_config_for_language_id(&self, id: &str) -> Option<Arc<LanguageConfiguration>> {
|
||||||
|
self.language_configs
|
||||||
|
.iter()
|
||||||
|
.find(|config| config.language_id == id)
|
||||||
|
.cloned()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn language_configuration_for_injection_string(
|
pub fn language_configuration_for_injection_string(
|
||||||
&self,
|
&self,
|
||||||
string: &str,
|
string: &str,
|
||||||
|
@ -529,6 +536,10 @@ impl Loader {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn language_configs(&self) -> impl Iterator<Item = &Arc<LanguageConfiguration>> {
|
||||||
|
self.language_configs.iter()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_scopes(&self, scopes: Vec<String>) {
|
pub fn set_scopes(&self, scopes: Vec<String>) {
|
||||||
self.scopes.store(Arc::new(scopes));
|
self.scopes.store(Arc::new(scopes));
|
||||||
|
|
||||||
|
|
|
@ -217,6 +217,7 @@ fn write_impl(cx: &mut compositor::Context, path: Option<&Cow<str>>) -> anyhow::
|
||||||
|
|
||||||
if path.is_some() {
|
if path.is_some() {
|
||||||
let id = doc.id();
|
let id = doc.id();
|
||||||
|
doc.detect_language(cx.editor.syn_loader.clone());
|
||||||
let _ = cx.editor.refresh_language_server(id);
|
let _ = cx.editor.refresh_language_server(id);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -931,6 +932,24 @@ fn setting(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Change the language of the current buffer at runtime.
|
||||||
|
fn language(
|
||||||
|
cx: &mut compositor::Context,
|
||||||
|
args: &[Cow<str>],
|
||||||
|
_event: PromptEvent,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
if args.len() != 1 {
|
||||||
|
anyhow::bail!("Bad arguments. Usage: `:set-language language`");
|
||||||
|
}
|
||||||
|
|
||||||
|
let doc = doc_mut!(cx.editor);
|
||||||
|
doc.set_language_by_language_id(&args[0], cx.editor.syn_loader.clone());
|
||||||
|
|
||||||
|
let id = doc.id();
|
||||||
|
cx.editor.refresh_language_server(id);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn sort(
|
fn sort(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
|
@ -1408,6 +1427,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
|
||||||
fun: goto_line_number,
|
fun: goto_line_number,
|
||||||
completer: None,
|
completer: None,
|
||||||
},
|
},
|
||||||
|
TypableCommand {
|
||||||
|
name: "set-language",
|
||||||
|
aliases: &["lang"],
|
||||||
|
doc: "Set the language of current buffer.",
|
||||||
|
fun: language,
|
||||||
|
completer: Some(completers::language),
|
||||||
|
},
|
||||||
TypableCommand {
|
TypableCommand {
|
||||||
name: "set-option",
|
name: "set-option",
|
||||||
aliases: &["set"],
|
aliases: &["set"],
|
||||||
|
|
|
@ -298,6 +298,27 @@ pub mod completers {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn language(editor: &Editor, input: &str) -> Vec<Completion> {
|
||||||
|
let matcher = Matcher::default();
|
||||||
|
|
||||||
|
let mut matches: Vec<_> = editor
|
||||||
|
.syn_loader
|
||||||
|
.language_configs()
|
||||||
|
.filter_map(|config| {
|
||||||
|
matcher
|
||||||
|
.fuzzy_match(&config.language_id, input)
|
||||||
|
.map(|score| (&config.language_id, score))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
matches.sort_unstable_by_key(|(_language, score)| Reverse(*score));
|
||||||
|
|
||||||
|
matches
|
||||||
|
.into_iter()
|
||||||
|
.map(|(language, _score)| ((0..), language.clone().into()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn directory(_editor: &Editor, input: &str) -> Vec<Completion> {
|
pub fn directory(_editor: &Editor, input: &str) -> Vec<Completion> {
|
||||||
filename_impl(input, |entry| {
|
filename_impl(input, |entry| {
|
||||||
let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir());
|
let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir());
|
||||||
|
|
|
@ -607,6 +607,17 @@ impl Document {
|
||||||
self.set_language(language_config, Some(config_loader));
|
self.set_language(language_config, Some(config_loader));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the programming language for the file if you know the language but don't have the
|
||||||
|
/// [`syntax::LanguageConfiguration`] for it.
|
||||||
|
pub fn set_language_by_language_id(
|
||||||
|
&mut self,
|
||||||
|
language_id: &str,
|
||||||
|
config_loader: Arc<syntax::Loader>,
|
||||||
|
) {
|
||||||
|
let language_config = config_loader.language_config_for_language_id(language_id);
|
||||||
|
self.set_language(language_config, Some(config_loader));
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the LSP.
|
/// Set the LSP.
|
||||||
pub fn set_language_server(&mut self, language_server: Option<Arc<helix_lsp::Client>>) {
|
pub fn set_language_server(&mut self, language_server: Option<Arc<helix_lsp::Client>>) {
|
||||||
self.language_server = language_server;
|
self.language_server = language_server;
|
||||||
|
|
|
@ -448,7 +448,6 @@ impl Editor {
|
||||||
/// Refreshes the language server for a given document
|
/// Refreshes the language server for a given document
|
||||||
pub fn refresh_language_server(&mut self, doc_id: DocumentId) -> Option<()> {
|
pub fn refresh_language_server(&mut self, doc_id: DocumentId) -> Option<()> {
|
||||||
let doc = self.documents.get_mut(&doc_id)?;
|
let doc = self.documents.get_mut(&doc_id)?;
|
||||||
doc.detect_language(self.syn_loader.clone());
|
|
||||||
Self::launch_language_server(&mut self.language_servers, doc)
|
Self::launch_language_server(&mut self.language_servers, doc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue