Skip to content

Commit

Permalink
Separate tab_width and indent_width:
Browse files Browse the repository at this point in the history
- tab_width is the width (in spaces) the `\t` character is rendered at
- indent_width is the width (in spaces) of an indentation level
Some functions previously incorrectly used tab_width for both.
  • Loading branch information
Triton171 committed Feb 11, 2023
1 parent e27fc06 commit e92990f
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 35 deletions.
21 changes: 17 additions & 4 deletions helix-core/src/indent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ use crate::{
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct IndentStyle {
pub unit: IndentUnit,
/// The width (in spaces) of a level of indentation. This is used:
/// - to insert the correct number of spaces, if unit == IndentUnit::Spaces
/// - to convert the number of spaces in an existing line into an indentation level
pub indent_width: usize,
/// The width that tabs are rendered at. This also determines how many
/// spaces a tab corresponds to when computing the indentation level for an existing line.
pub tab_width: usize,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
Expand All @@ -38,19 +44,23 @@ impl IndentStyle {
if indent.starts_with(' ') {
IndentStyle {
unit: IndentUnit::Spaces,
tab_width: indent.len(),
indent_width: indent.len(),
tab_width,
}
} else {
IndentStyle {
unit: IndentUnit::Tabs,
// TODO: Theoretically, one could define several tabs as an indent unit (which this code simply ignores).
// Supporting arbitrary indentation styles would require refactoring the `as_str` method though.
indent_width: tab_width,
tab_width,
}
}
}

#[inline]
pub fn as_str(&self) -> &'static str {
match (self.unit, self.tab_width) {
match (self.unit, self.indent_width) {
(IndentUnit::Tabs, _) => "\t",
(IndentUnit::Spaces, 1) => " ",
(IndentUnit::Spaces, 2) => " ",
Expand Down Expand Up @@ -182,11 +192,13 @@ pub fn auto_detect_indent_style(document_text: &Rope, tab_width: usize) -> Optio
Some(match indent {
0 => IndentStyle {
unit: IndentUnit::Tabs,
indent_width: tab_width,
tab_width,
},
_ => IndentStyle {
unit: IndentUnit::Spaces,
tab_width: indent,
indent_width: indent,
tab_width,
},
})
} else {
Expand All @@ -206,7 +218,7 @@ pub fn indent_level_for_line(line: RopeSlice, indent_style: &IndentStyle) -> usi
}
}

len / indent_style.tab_width
len / indent_style.indent_width
}

/// Computes for node and all ancestors whether they are the first node on their line.
Expand Down Expand Up @@ -781,6 +793,7 @@ mod test {
fn test_indent_level() {
let indent_style = IndentStyle {
unit: IndentUnit::Spaces,
indent_width: 4,
tab_width: 4,
};
let line = Rope::from(" fn new"); // 8 spaces
Expand Down
1 change: 1 addition & 0 deletions helix-core/tests/indent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ fn test_treesitter_indent(file_name: &str, lang_scope: &str) {
&syntax,
&IndentStyle {
unit: helix_core::indent::IndentUnit::Spaces,
indent_width: 4,
tab_width: 4,
},
text,
Expand Down
25 changes: 9 additions & 16 deletions helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -879,7 +879,7 @@ fn align_selections(cx: &mut Context) {
let text = doc.text().slice(..);
let selection = doc.selection(view.id);

let tab_width = doc.tab_width();
let tab_width = doc.indent_style.tab_width;
let mut column_widths: Vec<Vec<_>> = Vec::new();
let mut last_line = text.len_lines() + 1;
let mut col = 0;
Expand Down Expand Up @@ -1570,7 +1570,7 @@ fn copy_selection_on_line(cx: &mut Context, direction: Direction) {
(range.head, range.anchor.saturating_sub(1))
};

let tab_width = doc.tab_width();
let tab_width = doc.indent_style.tab_width;

let head_pos = visual_coords_at_pos(text, head, tab_width);
let anchor_pos = visual_coords_at_pos(text, anchor, tab_width);
Expand Down Expand Up @@ -3363,8 +3363,6 @@ pub mod insert {
let count = cx.count();
let (view, doc) = current_ref!(cx.editor);
let text = doc.text().slice(..);
let indent_unit = doc.indent_style.as_str();
let tab_size = doc.tab_width();
let auto_pairs = doc.auto_pairs(cx.editor);

let transaction =
Expand All @@ -3385,28 +3383,23 @@ pub mod insert {
None,
)
} else {
let unit_len = indent_unit.chars().count();
// NOTE: indent_unit always contains 'only spaces' or 'only tab' according to `IndentStyle` definition.
let unit_size = if indent_unit.starts_with('\t') {
tab_size * unit_len
} else {
unit_len
};
let tab_width = doc.indent_style.tab_width;
let indent_width = doc.indent_style.indent_width;
let width: usize = fragment
.chars()
.map(|ch| {
if ch == '\t' {
tab_size
tab_width
} else {
// it can be none if it still meet control characters other than '\t'
// here just set the width to 1 (or some value better?).
ch.width().unwrap_or(1)
}
})
.sum();
let mut drop = width % unit_size; // round down to nearest unit
let mut drop = width % indent_width; // round down to nearest unit
if drop == 0 {
drop = unit_size
drop = indent_width
}; // if it's already at a unit, consume a whole unit
let mut chars = fragment.chars().rev();
let mut start = pos;
Expand Down Expand Up @@ -3947,8 +3940,8 @@ fn unindent(cx: &mut Context) {
let (view, doc) = current!(cx.editor);
let lines = get_lines(doc, view.id);
let mut changes = Vec::with_capacity(lines.len());
let tab_width = doc.tab_width();
let indent_width = count * tab_width;
let tab_width = doc.indent_style.tab_width;
let indent_width = count * doc.indent_style.indent_width;

for line_idx in lines {
let line = doc.text().line(line_idx);
Expand Down
14 changes: 7 additions & 7 deletions helix-term/src/commands/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,11 +387,13 @@ fn set_indent_style(
IndentStyle { unit: Tabs, .. } => "tabs".to_owned(),
IndentStyle {
unit: Spaces,
tab_width: 1,
indent_width: 1,
..
} => "1 space".to_owned(),
IndentStyle {
unit: Spaces,
tab_width: n,
indent_width: n,
..
} if (2..=8).contains(&n) => format!("{} spaces", n),
_ => unreachable!(), // Shouldn't happen.
});
Expand All @@ -405,15 +407,13 @@ fn set_indent_style(
doc.indent_style.unit = Tabs;
}
arg => {
let tab_width = arg
let new_width = arg
.and_then(|arg| arg.parse::<usize>().ok())
.filter(|n| (1..=8).contains(n))
.context("invalid indent style")?;
let doc = doc_mut!(cx.editor);
doc.indent_style = IndentStyle {
unit: Spaces,
tab_width,
};
doc.indent_style.unit = Spaces;
doc.indent_style.indent_width = new_width;
}
}
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion helix-term/src/ui/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ impl<'a> TextRenderer<'a> {
characters: ws_chars,
} = &editor_config.whitespace;

let tab_width = doc.tab_width();
let tab_width = doc.indent_style.tab_width;
let tab = if ws_render.tab() == WhitespaceRenderValue::All {
std::iter::once(ws_chars.tab)
.chain(std::iter::repeat(ws_chars.tabpad).take(tab_width - 1))
Expand Down
10 changes: 3 additions & 7 deletions helix-view/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const BUF_SIZE: usize = 8192;

const DEFAULT_INDENT: IndentStyle = IndentStyle {
unit: IndentUnit::Tabs,
indent_width: 4,
tab_width: 4,
};

Expand Down Expand Up @@ -514,7 +515,7 @@ impl Document {
let request = language_server.text_document_formatting(
self.identifier(),
lsp::FormattingOptions {
tab_size: self.tab_width() as u32,
tab_size: self.indent_style.tab_width as u32,
insert_spaces: self.indent_style.unit == IndentUnit::Spaces,
..Default::default()
},
Expand Down Expand Up @@ -1129,11 +1130,6 @@ impl Document {
self.syntax.as_ref()
}

/// Tab size in columns.
pub fn tab_width(&self) -> usize {
self.indent_style.tab_width
}

pub fn changes(&self) -> &ChangeSet {
&self.changes
}
Expand Down Expand Up @@ -1244,7 +1240,7 @@ impl Document {
}
let config = self.config.load();
let soft_wrap = &config.soft_wrap;
let tab_width = self.tab_width() as u16;
let tab_width = self.indent_style.tab_width as u16;
TextFormat {
soft_wrap: soft_wrap.enable && viewport_width > 10,
tab_width,
Expand Down

0 comments on commit e92990f

Please sign in to comment.