Try to detect language when document file path is set

Fixes #91
This commit is contained in:
Blaž Hrastnik 2021-06-04 10:50:03 +09:00
parent 8afd4e1bc2
commit 06d8d3f55f
5 changed files with 59 additions and 43 deletions

View file

@ -251,22 +251,25 @@ where
Configuration, IndentationConfiguration, Lang, LanguageConfiguration, Loader, Configuration, IndentationConfiguration, Lang, LanguageConfiguration, Loader,
}; };
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
let loader = Loader::new(Configuration { let loader = Loader::new(
language: vec![LanguageConfiguration { Configuration {
scope: "source.rust".to_string(), language: vec![LanguageConfiguration {
file_types: vec!["rs".to_string()], scope: "source.rust".to_string(),
language_id: Lang::Rust, file_types: vec!["rs".to_string()],
highlight_config: OnceCell::new(), language_id: Lang::Rust,
// highlight_config: OnceCell::new(),
roots: vec![], //
language_server: None, roots: vec![],
indent: Some(IndentationConfiguration { language_server: None,
tab_width: 4, indent: Some(IndentationConfiguration {
unit: String::from(" "), tab_width: 4,
}), unit: String::from(" "),
indent_query: OnceCell::new(), }),
}], indent_query: OnceCell::new(),
}); }],
},
Vec::new(),
);
// set runtime path so we can find the queries // set runtime path so we can find the queries
let mut runtime = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); let mut runtime = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));

View file

@ -166,13 +166,15 @@ pub struct Loader {
// highlight_names ? // highlight_names ?
language_configs: Vec<Arc<LanguageConfiguration>>, language_configs: Vec<Arc<LanguageConfiguration>>,
language_config_ids_by_file_type: HashMap<String, usize>, // Vec<usize> language_config_ids_by_file_type: HashMap<String, usize>, // Vec<usize>
scopes: Vec<String>,
} }
impl Loader { impl Loader {
pub fn new(config: Configuration) -> Self { pub fn new(config: Configuration, scopes: Vec<String>) -> Self {
let mut loader = Self { let mut loader = Self {
language_configs: Vec::new(), language_configs: Vec::new(),
language_config_ids_by_file_type: HashMap::new(), language_config_ids_by_file_type: HashMap::new(),
scopes,
}; };
for config in config.language { for config in config.language {
@ -192,6 +194,10 @@ impl Loader {
loader loader
} }
pub fn scopes(&self) -> &[String] {
&self.scopes
}
pub fn language_config_for_file_name(&self, path: &Path) -> Option<Arc<LanguageConfiguration>> { pub fn language_config_for_file_name(&self, path: &Path) -> Option<Arc<LanguageConfiguration>> {
// Find all the language configurations that match this file name // Find all the language configurations that match this file name
// or a suffix of the file name. // or a suffix of the file name.

View file

@ -152,18 +152,6 @@ FLAGS:
setup_logging(logpath, args.verbosity).context("failed to initialize logging")?; setup_logging(logpath, args.verbosity).context("failed to initialize logging")?;
// initialize language registry
use helix_core::syntax::{Loader, LOADER};
// load $HOME/.config/helix/languages.toml, fallback to default config
let config = std::fs::read(helix_core::config_dir().join("languages.toml"));
let toml = config
.as_deref()
.unwrap_or(include_bytes!("../../languages.toml"));
let config = toml::from_slice(toml).context("Could not parse languages.toml")?;
LOADER.get_or_init(|| Loader::new(config));
// TODO: use the thread local executor to spawn the application task separately from the work pool // TODO: use the thread local executor to spawn the application task separately from the work pool
let mut app = Application::new(args).context("unable to create new appliction")?; let mut app = Application::new(args).context("unable to create new appliction")?;
app.run().await; app.run().await;

View file

@ -131,9 +131,8 @@ impl Document {
} }
} }
// TODO: passing scopes here is awkward
// TODO: async fn? // TODO: async fn?
pub fn load(path: PathBuf, scopes: &[String]) -> Result<Self, Error> { pub fn load(path: PathBuf) -> Result<Self, Error> {
use std::{env, fs::File, io::BufReader}; use std::{env, fs::File, io::BufReader};
let _current_dir = env::current_dir()?; let _current_dir = env::current_dir()?;
@ -143,15 +142,8 @@ impl Document {
// TODO: create if not found // TODO: create if not found
let mut doc = Self::new(doc); let mut doc = Self::new(doc);
// set the path and try detecting the language
let language_config = LOADER doc.set_path(&path)?;
.get()
.unwrap()
.language_config_for_file_name(path.as_path());
doc.set_language(language_config, scopes);
// canonicalize path to absolute value
doc.path = Some(std::fs::canonicalize(path)?);
Ok(doc) Ok(doc)
} }
@ -218,6 +210,15 @@ impl Document {
} }
} }
fn detect_language(&mut self) {
if let Some(path) = self.path() {
let loader = LOADER.get().unwrap();
let language_config = loader.language_config_for_file_name(path);
let scopes = loader.scopes();
self.set_language(language_config, scopes);
}
}
pub fn set_path(&mut self, path: &Path) -> Result<(), std::io::Error> { pub fn set_path(&mut self, path: &Path) -> Result<(), std::io::Error> {
// canonicalize path to absolute value // canonicalize path to absolute value
let current_dir = std::env::current_dir()?; let current_dir = std::env::current_dir()?;
@ -229,6 +230,10 @@ impl Document {
self.path = Some(path); self.path = Some(path);
} }
} }
// try detecting the language based on filepath
self.detect_language();
Ok(()) Ok(())
} }
@ -251,8 +256,10 @@ impl Document {
}; };
} }
pub fn set_language2(&mut self, scope: &str, scopes: &[String]) { pub fn set_language2(&mut self, scope: &str) {
let language_config = LOADER.get().unwrap().language_config_for_scope(scope); let loader = LOADER.get().unwrap();
let language_config = loader.language_config_for_scope(scope);
let scopes = loader.scopes();
self.set_language(language_config, scopes); self.set_language(language_config, scopes);
} }

View file

@ -36,6 +36,18 @@ impl Editor {
.unwrap_or(include_bytes!("../../theme.toml")); .unwrap_or(include_bytes!("../../theme.toml"));
let theme: Theme = toml::from_slice(toml).expect("failed to parse theme.toml"); let theme: Theme = toml::from_slice(toml).expect("failed to parse theme.toml");
// initialize language registry
use helix_core::syntax::{Loader, LOADER};
// load $HOME/.config/helix/languages.toml, fallback to default config
let config = std::fs::read(helix_core::config_dir().join("languages.toml"));
let toml = config
.as_deref()
.unwrap_or(include_bytes!("../../languages.toml"));
let config = toml::from_slice(toml).expect("Could not parse languages.toml");
LOADER.get_or_init(|| Loader::new(config, theme.scopes().to_vec()));
let language_servers = helix_lsp::Registry::new(); let language_servers = helix_lsp::Registry::new();
// HAXX: offset the render area height by 1 to account for prompt/commandline // HAXX: offset the render area height by 1 to account for prompt/commandline
@ -135,7 +147,7 @@ impl Editor {
let id = if let Some(id) = id { let id = if let Some(id) = id {
id id
} else { } else {
let mut doc = Document::load(path, self.theme.scopes())?; let mut doc = Document::load(path)?;
// try to find a language server based on the language name // try to find a language server based on the language name
let language_server = doc let language_server = doc