···
30
30
were ignored.
31
31
([Francesco Cappetti](https://github.com/frakappa))
32
32
33
33
+
- Fixed a bug where the language server would crash on code that contains syntax
34
34
+
errors.
35
35
+
([Giacomo Cavalieri](https://github.com/giacomocavalieri))
36
36
+
37
37
+
- Fixed a bug where bit array segments would not be compiled properly, using an
38
38
+
invalid Erlang segment option.
39
39
+
([Giacomo Cavalieri](https://github.com/giacomocavalieri))
40
40
+
33
41
## v1.18.0-rc1 - 2026-07-21
34
42
35
43
### Compiler
···
12992
12992
12993
12993
pub fn code_actions(self) -> Vec<CodeAction> {
12994
12994
let line = self.params.range.start.line;
12995
12995
-
let num_slashes = self
12996
12996
-
.count_leading_slashes(line)
12997
12997
-
.expect("Line number should be valid");
12995
12995
+
let Some(num_slashes) = self.count_leading_slashes(line) else {
12996
12996
+
return vec![];
12997
12997
+
};
12998
12998
12999
12999
if !(2..=4).contains(&num_slashes) {
13000
13000
return vec![];
···
13012
13012
}
13013
13013
13014
13014
let comment = match num_slashes {
13015
13015
-
2 if self.is_module_comment(start_line, end_line) => "////",
13015
13015
+
2 if self.can_be_module_comment(start_line, end_line) => "////",
13016
13016
2 if self.can_have_doc_comment(end_line) => "///",
13017
13017
3 | 4 => "//",
13018
13018
_ => return vec![],
···
13020
13020
13021
13021
let mut edits = TextEdits::new(self.lines);
13022
13022
for line in start_line..=end_line {
13023
13023
-
let start = next_nonwhitespace(
13024
13024
-
&self.module.code,
13025
13025
-
self.line_start(line).expect("Line number should be valid"),
13026
13026
-
);
13023
13023
+
let Some(line_start) = self.line_start(line) else {
13024
13024
+
return vec![];
13025
13025
+
};
13026
13026
+
let start = next_nonwhitespace(&self.module.code, line_start);
13027
13027
edits.replace(SrcSpan::new(start, start + num_slashes), comment.to_owned());
13028
13028
}
13029
13029
···
13058
13058
}
13059
13059
13060
13060
/// Find the last line in the range that is part of the same comment.
13061
13061
-
fn find_comment_edge(&self, range: impl Iterator<Item = u32>, num_slashes: u32) -> Option<u32> {
13062
13062
-
range
13063
13063
-
.take_while(|&i| {
13064
13064
-
self.count_leading_slashes(i)
13061
13061
+
fn find_comment_edge(&self, lines: impl Iterator<Item = u32>, num_slashes: u32) -> Option<u32> {
13062
13062
+
lines
13063
13063
+
.take_while(|&line| {
13064
13064
+
self.count_leading_slashes(line)
13065
13065
.is_some_and(|n| n == num_slashes)
13066
13066
})
13067
13067
.last()
13068
13068
}
13069
13069
13070
13070
-
fn is_module_comment(&self, start_line: u32, end_line: u32) -> bool {
13071
13071
-
previous_nonwhitespace(
13072
13072
-
&self.module.code,
13073
13073
-
self.line_start(start_line)
13074
13074
-
.expect("Line number should be valid"),
13075
13075
-
) == 0
13070
13070
+
fn can_be_module_comment(&self, start_line: u32, end_line: u32) -> bool {
13071
13071
+
let Some(line_start) = self.line_start(start_line) else {
13072
13072
+
return false;
13073
13073
+
};
13074
13074
+
previous_nonwhitespace(&self.module.code, line_start) == 0
13076
13075
&& self
13077
13076
.line_start(end_line + 1)
13078
13077
.is_none_or(|position| self.module.extra.empty_lines.contains(&position))
···
13080
13079
13081
13080
/// Check if the comment is before a node that can have a doc comment, e.g. a function.
13082
13081
fn can_have_doc_comment(&self, end_line: u32) -> bool {
13083
13083
-
self.line_start(end_line + 1).is_some_and(|position| {
13084
13084
-
let next_node = next_nonwhitespace(&self.module.code, position);
13085
13085
-
let definitions = &self.module.ast.definitions;
13086
13086
-
definitions
13087
13087
-
.functions
13082
13082
+
let Some(position) = self.line_start(end_line + 1) else {
13083
13083
+
return false;
13084
13084
+
};
13085
13085
+
13086
13086
+
let next_node = next_nonwhitespace(&self.module.code, position);
13087
13087
+
let definitions = &self.module.ast.definitions;
13088
13088
+
definitions
13089
13089
+
.functions
13090
13090
+
.iter()
13091
13091
+
.any(|function| function.location.contains(next_node))
13092
13092
+
|| definitions
13093
13093
+
.constants
13088
13094
.iter()
13089
13089
-
.any(|function| function.location.contains(next_node))
13090
13090
-
|| definitions
13091
13091
-
.constants
13092
13092
-
.iter()
13093
13093
-
.any(|constant| constant.location.contains(next_node))
13094
13094
-
|| definitions
13095
13095
-
.type_aliases
13096
13096
-
.iter()
13097
13097
-
.any(|type_alias| type_alias.location.contains(next_node))
13098
13098
-
|| definitions.custom_types.iter().any(|custom_type| {
13099
13099
-
custom_type.location.contains(next_node)
13100
13100
-
|| custom_type.constructors.iter().any(|constructor| {
13101
13101
-
constructor.location.contains(next_node)
13102
13102
-
|| constructor.arguments.iter().any(|argument| {
13103
13103
-
argument
13104
13104
-
.label
13105
13105
-
.as_ref()
13106
13106
-
.is_some_and(|label| label.0.contains(next_node))
13107
13107
-
})
13108
13108
-
})
13109
13109
-
})
13110
13110
-
})
13095
13095
+
.any(|constant| constant.location.contains(next_node))
13096
13096
+
|| definitions
13097
13097
+
.type_aliases
13098
13098
+
.iter()
13099
13099
+
.any(|type_alias| type_alias.location.contains(next_node))
13100
13100
+
|| definitions.custom_types.iter().any(|custom_type| {
13101
13101
+
custom_type.location.contains(next_node)
13102
13102
+
|| custom_type.constructors.iter().any(|constructor| {
13103
13103
+
constructor.location.contains(next_node)
13104
13104
+
|| constructor.arguments.iter().any(|argument| {
13105
13105
+
argument
13106
13106
+
.label
13107
13107
+
.as_ref()
13108
13108
+
.is_some_and(|label| label.0.contains(next_node))
13109
13109
+
})
13110
13110
+
})
13111
13111
+
})
13111
13112
}
13112
13113
}
13113
13114