Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tree-sitter-htmldjango #3249

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions book/src/generated/lang-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
| hcl | ✓ | | ✓ | `terraform-ls` |
| heex | ✓ | ✓ | | |
| html | ✓ | | | `vscode-html-language-server` |
| htmldjango | ✓ | | ✓ | |
| idris | | | | `idris2-lsp` |
| iex | ✓ | | | |
| java | ✓ | | | `jdtls` |
Expand Down
52 changes: 43 additions & 9 deletions helix-core/src/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -436,8 +436,8 @@ impl LanguageConfiguration {
pub struct Loader {
// highlight_names ?
language_configs: Vec<Arc<LanguageConfiguration>>,
language_config_ids_by_file_type: HashMap<String, usize>, // Vec<usize>
language_config_ids_by_shebang: HashMap<String, usize>,
language_config_ids_by_file_type: HashMap<String, Vec<usize>>, // Vec<usize>
language_config_ids_by_shebang: HashMap<String, Vec<usize>>,

scopes: ArcSwap<Vec<String>>,
}
Expand All @@ -456,15 +456,18 @@ impl Loader {
let language_id = loader.language_configs.len();

for file_type in &config.file_types {
// entry().or_insert(Vec::new).push(language_id);
loader
.language_config_ids_by_file_type
.insert(file_type.clone(), language_id);
.entry(file_type.clone())
.or_insert_with(Vec::new)
.push(language_id);
}
for shebang in &config.shebangs {
loader
.language_config_ids_by_shebang
.insert(shebang.clone(), language_id);
.entry(shebang.clone())
.or_insert_with(Vec::new)
.push(language_id);
}

loader.language_configs.push(Arc::new(config));
Expand All @@ -476,7 +479,7 @@ impl Loader {
pub fn language_config_for_file_name(&self, path: &Path) -> Option<Arc<LanguageConfiguration>> {
// Find all the language configurations that match this file name
// or a suffix of the file name.
let configuration_id = path
let configuration_ids = path
.file_name()
.and_then(|n| n.to_str())
.and_then(|file_name| self.language_config_ids_by_file_type.get(file_name))
Expand All @@ -485,6 +488,35 @@ impl Loader {
.and_then(|extension| extension.to_str())
.and_then(|extension| self.language_config_ids_by_file_type.get(extension))
});
// If there are more than one match, try to see if any of the roots
// matches to reduce the results.
let configuration_id = match configuration_ids.as_ref() {
Some(ids) => match &ids[..] {
[id] => Some(id),
ids => ids
.iter()
// prioritize language configs with root
.find(|&id| {
let roots = &self.language_configs[*id].roots;
if roots.is_empty() {
return false;
}
// check if specified roots is in search root path
let root = helix_loader::search_root(path.to_str());
for ancestor in root.ancestors() {
if roots.iter().any(|marker| ancestor.join(marker).exists()) {
return true;
// but don't go higher than repo
} else if ancestor.join(".git").is_dir() {
return false;
}
}
false
})
.or_else(|| ids.first()),
},
None => None,
};

configuration_id.and_then(|&id| self.language_configs.get(id).cloned())

Expand All @@ -496,9 +528,11 @@ impl Loader {
static SHEBANG_REGEX: Lazy<Regex> = Lazy::new(|| {
Regex::new(r"^#!\s*(?:\S*[/\\](?:env\s+(?:\-\S+\s+)*)?)?([^\s\.\d]+)").unwrap()
});
let configuration_id = SHEBANG_REGEX
.captures(&line)
.and_then(|cap| self.language_config_ids_by_shebang.get(&cap[1]));
let configuration_id = SHEBANG_REGEX.captures(&line).and_then(|cap| {
self.language_config_ids_by_shebang
.get(&cap[1])
.map(|ids| ids.first().unwrap())
});

configuration_id.and_then(|&id| self.language_configs.get(id).cloned())
}
Expand Down
24 changes: 14 additions & 10 deletions helix-loader/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ pub mod config;
pub mod grammar;

use etcetera::base_strategy::{choose_base_strategy, BaseStrategy};
use std::path::PathBuf;
use std::path::{Path, PathBuf};

pub static RUNTIME_DIR: once_cell::sync::Lazy<PathBuf> = once_cell::sync::Lazy::new(runtime_dir);

Expand Down Expand Up @@ -88,21 +88,25 @@ pub fn log_file() -> PathBuf {
cache_dir().join("helix.log")
}

pub fn find_root_impl(root: Option<&str>, root_markers: &[String]) -> Vec<PathBuf> {
let current_dir = std::env::current_dir().expect("unable to determine current directory");
let mut directories = Vec::new();

let root = match root {
/// Get root to search until.
pub fn search_root(root: Option<&str>) -> PathBuf {
let current_dir = || std::env::current_dir().expect("unable to determine current directory");
match root {
Some(root) => {
let root = std::path::Path::new(root);
let root = Path::new(root);
if root.is_absolute() {
root.to_path_buf()
} else {
current_dir.join(root)
current_dir().join(root)
}
}
None => current_dir,
};
None => current_dir(),
}
}

pub fn find_root_impl(root: Option<&str>, root_markers: &[String]) -> Vec<PathBuf> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite know why are we not using Path here, but I don't feel like changing this here.

let root = search_root(root);
let mut directories = Vec::new();

for ancestor in root.ancestors() {
// don't go higher than repo
Expand Down
12 changes: 12 additions & 0 deletions languages.toml
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,18 @@ indent = { tab-width = 2, unit = " " }
name = "html"
source = { git = "https://github.com/tree-sitter/tree-sitter-html", rev = "d93af487cc75120c89257195e6be46c999c6ba18" }

[[language]]
name = "htmldjango"
scope = "source.htmldjango"
injection-regex = "htmldjango"
file-types = ["html"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this entry beats regular html for .html files. We have another conflict like this between verilog and V and I think the only way around it for now is to have one of them where you have to override it in a .helix/languages.toml or ~/.config/helix/languages.toml:

[[language]]
name = "html"
file-types = []

[[language]]
name = "htmldjango"
file-types = ["html"]

Since HTML is more popular than django I think we should disable this language by default

Suggested change
file-types = ["html"]
file-types = []

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it beats html, but doesn't it only apply if say the root file manage.py is found?

Copy link
Contributor Author

@pickfire pickfire Aug 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh wait, it doesn't. Maybe we should apply it conditionally based on the roots? I will take some time before I get to work on this later.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was also under the impression that file-types would only be superceded if manage.py was found based on these settings, a file I've never heard of or seen people using until I did some web searching based on this PR's options. I'll need to re-read those options.

Copy link
Contributor Author

@pickfire pickfire Aug 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be fixed now, but I am still a bit not quite happy with the result that the ordering is a bit messy (it will take the first glob that matches the path and have the root within the path). Some parts of it were taken from #2455, but I haven't updated the docs yet.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be fixed now, but I am still a bit not quite happy with the result that the ordering is a bit messy (it will take the first glob that matches the path and have the root within the path). Some parts of it was taken from #2455, but I haven't updated the docs yet.

roots = ["manage.py"]
indent = { tab-width = 2, unit = " " }

[[grammar]]
name = "htmldjango"
source = { git = "https://github.com/interdependence/tree-sitter-htmldjango", rev = "184a50456186c2ff49b9b410f7060a176e2a3080" }

[[language]]
name = "python"
scope = "source.python"
Expand Down
25 changes: 25 additions & 0 deletions runtime/queries/htmldjango/highlights.scm
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[
(unpaired_comment)
(paired_comment)
] @comment

[
"{{"
"}}"
"{%"
"%}"
(end_paired_statement)
] @tag

"end" @keyword.return

(variable_name) @variable
(filter_name) @function.macro
(filter_argument) @variable.parameter
(tag_name) @function
(keyword) @keyword
(operator) @operator
(keyword_operator) @keyword.directive
(number) @constant.numeric
(boolean) @constant.builtin.boolean
(string) @string
2 changes: 2 additions & 0 deletions runtime/queries/htmldjango/indents.scm
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(paired_statement) @indent
(end_paired_statement) @outdent
Comment on lines +1 to +2
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking about this again, not sure if we want this since vim does not indent django paired statements.

6 changes: 6 additions & 0 deletions runtime/queries/htmldjango/injections.scm
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
((content) @injection.content
(#set! injection.language "html")
(#set! injection.combined))

([(unpaired_comment) (paired_comment)] @injection.content
(#set! injection.language "comment"))
2 changes: 2 additions & 0 deletions runtime/themes/monokai_pro_spectrum.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,12 @@
# operator, tags, units, punctuations
"operator" = "red"
"variable.other.member" = "base8"
"tag" = "yellow"

# keywords, special
"keyword" = { fg = "red" }
"keyword.directive" = "blue"
"keyword.function" = "blue"
"variable.parameter" = "#f59762"

# error
Expand Down