Skip to content
Open
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
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
resolver = "2"
resolver = "3"
members = [
"helix-core",
"helix-view",
Expand Down Expand Up @@ -60,7 +60,7 @@ arc-swap = "1.9"

[workspace.package]
version = "25.7.1"
edition = "2021"
edition = "2024"
authors = ["Blaž Hrastnik <blaz@mxxn.io>"]
categories = ["editor"]
repository = "https://github.com/helix-editor/helix"
Expand Down
9 changes: 5 additions & 4 deletions helix-core/src/auto_pairs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,11 @@ pub fn hook_delete(doc: &Rope, range: &Range, pairs: &AutoPairs) -> Option<(Dele
let second_next = doc.get_char(graphemes::next_grapheme_boundary(text, cursor))?;
log::debug!("second_prev: {}, second_next: {}", second_prev, second_next);

if let Some(pair) = pairs.get(second_prev) {
if pair.open == second_prev && pair.close == second_next {
return handle_delete(doc, range);
}
if let Some(pair) = pairs.get(second_prev)
&& pair.open == second_prev
&& pair.close == second_next
{
return handle_delete(doc, range);
}
}

Expand Down
5 changes: 2 additions & 3 deletions helix-core/src/doc_formatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,10 +239,9 @@ impl<'t> DocumentFormatter<'t> {
loop {
if let Some(&mut (ref mut annotation, highlight)) =
self.inline_annotation_graphemes.as_mut()
&& let Some(grapheme) = annotation.next()
{
if let Some(grapheme) = annotation.next() {
return Some((grapheme, highlight));
}
return Some((grapheme, highlight));
}

if let Some((annotation, highlight)) =
Expand Down
121 changes: 60 additions & 61 deletions helix-core/src/indent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,10 +295,11 @@ fn add_indent_level(
fn is_first_in_line(node: &Node, text: RopeSlice, new_line_byte_pos: Option<u32>) -> bool {
let line = text.byte_to_line(node.start_byte() as usize);
let mut line_start_byte_pos = text.line_to_byte(line) as u32;
if let Some(pos) = new_line_byte_pos {
if line_start_byte_pos < pos && pos <= node.start_byte() {
line_start_byte_pos = pos;
}
if let Some(pos) = new_line_byte_pos
&& line_start_byte_pos < pos
&& pos <= node.start_byte()
{
line_start_byte_pos = pos;
}
text.byte_slice(line_start_byte_pos as usize..node.start_byte() as usize)
.chars()
Expand Down Expand Up @@ -1020,67 +1021,65 @@ pub fn indent_for_newline(
indent_heuristic,
syntax.and_then(|syntax| loader.indent_query(syntax.root_language())),
syntax,
) && let Some(indent) = treesitter_indent_for_pos(
query,
syntax,
tab_width,
indent_width,
text,
line_before,
line_before_end_pos,
true,
) {
if let Some(indent) = treesitter_indent_for_pos(
query,
syntax,
tab_width,
indent_width,
text,
line_before,
line_before_end_pos,
true,
) {
if *indent_heuristic == IndentationHeuristic::Hybrid {
// We want to compute the indentation not only based on the
// syntax tree but also on the actual indentation of a previous
// line. This makes indentation computation more resilient to
// incomplete queries, incomplete source code & differing indentation
// styles for the same language.
// However, using the indent of a previous line as a baseline may not
// make sense, e.g. if it has a different alignment than the new line.
// In order to prevent edge cases with long running times, we only try
// a constant number of (non-empty) lines.
const MAX_ATTEMPTS: usize = 4;
let mut num_attempts = 0;
for line_idx in (0..=line_before).rev() {
let line = text.line(line_idx);
let first_non_whitespace_char = match line.first_non_whitespace_char() {
Some(i) => i,
None => {
continue;
}
};
if let Some(indent) = (|| {
let computed_indent = treesitter_indent_for_pos(
query,
syntax,
tab_width,
indent_width,
text,
line_idx,
text.line_to_char(line_idx) + first_non_whitespace_char,
false,
)?;
let leading_whitespace = line.slice(0..first_non_whitespace_char);
indent.relative_indent(
&computed_indent,
leading_whitespace,
indent_style,
tab_width,
)
})() {
return indent;
}
num_attempts += 1;
if num_attempts == MAX_ATTEMPTS {
break;
if *indent_heuristic == IndentationHeuristic::Hybrid {
// We want to compute the indentation not only based on the
// syntax tree but also on the actual indentation of a previous
// line. This makes indentation computation more resilient to
// incomplete queries, incomplete source code & differing indentation
// styles for the same language.
// However, using the indent of a previous line as a baseline may not
// make sense, e.g. if it has a different alignment than the new line.
// In order to prevent edge cases with long running times, we only try
// a constant number of (non-empty) lines.
const MAX_ATTEMPTS: usize = 4;
let mut num_attempts = 0;
for line_idx in (0..=line_before).rev() {
let line = text.line(line_idx);
let first_non_whitespace_char = match line.first_non_whitespace_char() {
Some(i) => i,
None => {
continue;
}
};
if let Some(indent) = (|| {
let computed_indent = treesitter_indent_for_pos(
query,
syntax,
tab_width,
indent_width,
text,
line_idx,
text.line_to_char(line_idx) + first_non_whitespace_char,
false,
)?;
let leading_whitespace = line.slice(0..first_non_whitespace_char);
indent.relative_indent(
&computed_indent,
leading_whitespace,
indent_style,
tab_width,
)
})() {
return indent;
}
num_attempts += 1;
if num_attempts == MAX_ATTEMPTS {
break;
}
}
return indent.to_string(indent_style, tab_width);
};
}
}
return indent.to_string(indent_style, tab_width);
};
// Fallback in case we either don't have indent queries or they failed for some reason
let indent_level = indent_level_for_line(text.line(current_line), tab_width, indent_width);
indent_style.as_str().repeat(indent_level)
Expand Down
39 changes: 19 additions & 20 deletions helix-core/src/match_brackets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,35 +92,34 @@ fn find_pair(

if let (Some((start_pos, open)), Some((end_pos, close))) =
(as_char(doc, &open), as_char(doc, &close))
&& PAIRS.contains(&(open, close))
&& start_pos <= pos_
&& pos_ <= end_pos
{
if PAIRS.contains(&(open, close)) && start_pos <= pos_ && pos_ <= end_pos {
if end_pos == pos_ {
return Some(start_pos);
}

// We return the end char if the cursor is either on the start char
// or at some arbitrary position between start and end char.
if traverse_parents || start_pos == pos_ {
return Some(end_pos);
}
if end_pos == pos_ {
return Some(start_pos);
}

// We return the end char if the cursor is either on the start char
// or at some arbitrary position between start and end char.
if traverse_parents || start_pos == pos_ {
return Some(end_pos);
}
}
}
// this node itselt wasn't a pair but maybe its siblings are

if let Some((start_char, end_char)) = as_close_pair(doc, &node) {
if let Some(pair_start) =
if let Some((start_char, end_char)) = as_close_pair(doc, &node)
&& let Some(pair_start) =
find_pair_end(doc, node.prev_sibling(), start_char, end_char, Backward)
{
return Some(pair_start);
}
{
return Some(pair_start);
}
if let Some((start_char, end_char)) = as_open_pair(doc, &node) {
if let Some(pair_end) =
if let Some((start_char, end_char)) = as_open_pair(doc, &node)
&& let Some(pair_end) =
find_pair_end(doc, node.next_sibling(), start_char, end_char, Forward)
{
return Some(pair_end);
}
{
return Some(pair_end);
}

if traverse_parents {
Expand Down
8 changes: 4 additions & 4 deletions helix-core/src/movement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -577,10 +577,10 @@ pub fn goto_treesitter_object(

let cap_name = |t: TextObject| format!("{}.{}", object_name, t);
let nodes = textobject_query?.capture_nodes_any(
&[
&cap_name(TextObject::Movement),
&cap_name(TextObject::Around),
&cap_name(TextObject::Inside),
[
cap_name(TextObject::Movement),
cap_name(TextObject::Around),
cap_name(TextObject::Inside),
],
slice_tree,
slice,
Expand Down
8 changes: 4 additions & 4 deletions helix-core/src/position.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,10 +230,10 @@ pub fn visual_offset_from_anchor(
}
}

if let Some(anchor_line) = anchor_line {
if grapheme.visual_pos.row >= anchor_line + max_rows {
return Err(VisualOffsetError::PosAfterMaxRow);
}
if let Some(anchor_line) = anchor_line
&& grapheme.visual_pos.row >= anchor_line + max_rows
{
return Err(VisualOffsetError::PosAfterMaxRow);
}
}

Expand Down
12 changes: 6 additions & 6 deletions helix-core/src/snippets/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,12 @@ fn text<'a>(
while let Some((i, c)) = chars.next() {
match c {
'\\' => {
if let Some(&(_, c)) = chars.peek() {
if escape_chars.contains(&c) {
chars.next();
res.push(c);
continue;
}
if let Some(&(_, c)) = chars.peek()
&& escape_chars.contains(&c)
{
chars.next();
res.push(c);
continue;
}
res.push('\\');
}
Expand Down
49 changes: 23 additions & 26 deletions helix-core/src/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,13 +360,13 @@ impl Loader {
let mut best_match_length = 0;
let mut best_match_position = None;
for (idx, data) in self.languages.iter().enumerate() {
if let Some(injection_regex) = &data.config.injection_regex {
if let Some(mat) = injection_regex.find(text.regex_input()) {
let length = mat.end() - mat.start();
if length > best_match_length {
best_match_position = Some(idx);
best_match_length = length;
}
if let Some(injection_regex) = &data.config.injection_regex
&& let Some(mat) = injection_regex.find(text.regex_input())
{
let length = mat.end() - mat.start();
if length > best_match_length {
best_match_position = Some(idx);
best_match_length = length;
}
}
}
Expand Down Expand Up @@ -679,20 +679,17 @@ impl Syntax {
},
highlight: Highlight::new((scope_stack.len() % rainbow_length) as u32),
});
} else if capture == rainbow_query.bracket_capture {
if let Some(scope) = scope_stack.last() {
if !scope
.node
.as_ref()
.is_some_and(|node| mat.node.parent().as_ref() != Some(node))
{
let start = source
.byte_to_char(source.floor_char_boundary(byte_range.start as usize));
let end =
source.byte_to_char(source.ceil_char_boundary(byte_range.end as usize));
highlights.push((scope.highlight, start..end));
}
}
} else if capture == rainbow_query.bracket_capture
&& let Some(scope) = scope_stack.last()
&& !scope
.node
.as_ref()
.is_some_and(|node| mat.node.parent().as_ref() != Some(node))
{
let start =
source.byte_to_char(source.floor_char_boundary(byte_range.start as usize));
let end = source.byte_to_char(source.ceil_char_boundary(byte_range.end as usize));
highlights.push((scope.highlight, start..end));
}
}

Expand Down Expand Up @@ -1036,20 +1033,20 @@ impl TextObjectQuery {
node: &Node<'a>,
slice: RopeSlice<'a>,
) -> Option<impl Iterator<Item = CapturedNode<'a>>> {
self.capture_nodes_any(&[capture_name], node, slice)
self.capture_nodes_any(iter::once(capture_name), node, slice)
}

/// Find the first capture that exists out of all given `capture_names`
/// and return sub nodes that match this capture.
pub fn capture_nodes_any<'a>(
pub fn capture_nodes_any<'a, S: AsRef<str>, I: IntoIterator<Item = S>>(
&'a self,
capture_names: &[&str],
capture_names: I,
node: &Node<'a>,
slice: RopeSlice<'a>,
) -> Option<impl Iterator<Item = CapturedNode<'a>>> {
let capture = capture_names
.iter()
.find_map(|cap| self.query.get_capture(cap))?;
.into_iter()
.find_map(|cap| self.query.get_capture(cap.as_ref()))?;

let mut cursor = InactiveQueryCursor::new(0..u32::MAX, TREE_SITTER_MATCH_LIMIT)
.execute_query(&self.query, node, RopeInput::new(slice));
Expand Down
2 changes: 1 addition & 1 deletion helix-core/src/text_annotations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ impl<T: ?Sized> RawBox<T> {
/// created by this function may exist at a given time.
#[allow(clippy::mut_from_ref)]
unsafe fn get(&self) -> &mut T {
&mut *self.0.as_ptr()
unsafe { &mut *self.0.as_ptr() }
}
}
impl<T: ?Sized> From<Box<T>> for RawBox<T> {
Expand Down
2 changes: 1 addition & 1 deletion helix-core/tests/indent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ fn test_treesitter_indent(
// set runtime path so we can find the queries
let mut runtime = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
runtime.push("../runtime");
std::env::set_var("HELIX_RUNTIME", runtime.to_str().unwrap());
unsafe { std::env::set_var("HELIX_RUNTIME", runtime.to_str().unwrap()) };

let language = loader.language_for_scope(lang_scope).unwrap();
let language_config = loader.language(language).config();
Expand Down
2 changes: 1 addition & 1 deletion helix-dap/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "helix-dap"
description = "DAP client implementation for Helix project"
version.workspace = true
authors.workspace = true
edition.workspace = true
edition = "2021"
license.workspace = true
rust-version.workspace = true
categories.workspace = true
Expand Down
Loading