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

Make gutters configurable #1967

Merged
merged 25 commits into from
Apr 16, 2022
Merged
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/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ hidden = false
| `scroll-lines` | Number of lines to scroll per scroll wheel step. | `3` |
| `shell` | Shell to use when running external commands. | Unix: `["sh", "-c"]`<br/>Windows: `["cmd", "/C"]` |
| `line-number` | Line number display: `absolute` simply shows each line's number, while `relative` shows the distance from the current line. When unfocused or in insert mode, `relative` will still show absolute line numbers. | `absolute` |
| `gutters` | Gutters to display: Available are `diagnostics` and `line-numbers`, note that `diagnostics` also includes other features like breakpoints | `["diagnostics", "line-numbers"]` |
| `auto-completion` | Enable automatic pop up of auto-completion. | `true` |
| `idle-timeout` | Time in milliseconds since last keypress before idle timers trigger. Used for autocompletion, set to 0 for instant. | `400` |
| `completion-trigger-len` | The min-length of word under cursor to trigger autocompletion | `2` |
Expand Down
2 changes: 1 addition & 1 deletion helix-term/src/ui/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ impl EditorView {
// avoid lots of small allocations by reusing a text buffer for each line
let mut text = String::with_capacity(8);

for (constructor, width) in view.gutters() {
for (constructor, width) in &view.gutters {
let gutter = constructor(editor, doc, view, theme, is_focused, *width);
text.reserve(*width); // ensure there's enough space for the gutter
for (i, line) in (view.offset.row..(last_line + 1)).enumerate() {
Expand Down
28 changes: 26 additions & 2 deletions helix-view/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ pub struct Config {
pub shell: Vec<String>,
/// Line number mode.
pub line_number: LineNumber,
/// Gutters. Default ["diagnostics", "line-numbers"]
pub gutters: Vec<GutterType>,
/// Middle click paste support. Defaults to true.
pub middle_click_paste: bool,
/// Automatic insertion of pairs to parentheses, brackets,
Expand Down Expand Up @@ -238,6 +240,27 @@ impl std::str::FromStr for LineNumber {
}
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum GutterType {
/// Show diagnostics and other features like breakpoints
Diagnostics,
/// Show line numbers
LineNumbers,
}

impl std::str::FromStr for GutterType {
type Err = anyhow::Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"diagnostics" => Ok(Self::Diagnostics),
"line-numbers" => Ok(Self::LineNumbers),
_ => anyhow::bail!("Gutter type can only be `diagnostics` or `line-numbers`."),
}
}
}

impl Default for Config {
fn default() -> Self {
Self {
Expand All @@ -250,6 +273,7 @@ impl Default for Config {
vec!["sh".to_owned(), "-c".to_owned()]
},
line_number: LineNumber::Absolute,
gutters: vec![GutterType::Diagnostics, GutterType::LineNumbers],
middle_click_paste: true,
auto_pairs: AutoPairConfig::default(),
auto_completion: true,
Expand Down Expand Up @@ -577,7 +601,7 @@ impl Editor {
return;
}
Action::HorizontalSplit | Action::VerticalSplit => {
let view = View::new(id);
let view = View::new(id, self.config().gutters.clone());
let view_id = self.tree.split(
view,
match action {
Expand Down Expand Up @@ -699,7 +723,7 @@ impl Editor {
.map(|(&doc_id, _)| doc_id)
.next()
.unwrap_or_else(|| self.new_document(Document::default()));
let view = View::new(doc_id);
let view = View::new(doc_id, self.config().gutters.clone());
let view_id = self.tree.insert(view);
let doc = self.documents.get_mut(&doc_id).unwrap();
doc.selections.insert(view_id, Selection::point(0));
Expand Down
2 changes: 1 addition & 1 deletion helix-view/src/gutter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub fn diagnostic<'doc>(
})
}

pub fn line_number<'doc>(
pub fn line_numbers<'doc>(
editor: &'doc Editor,
doc: &'doc Document,
view: &View,
Expand Down
21 changes: 17 additions & 4 deletions helix-view/src/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,7 @@ impl<'a> Iterator for Traverse<'a> {
#[cfg(test)]
mod test {
use super::*;
use crate::editor::GutterType;
use crate::DocumentId;

#[test]
Expand All @@ -578,22 +579,34 @@ mod test {
width: 180,
height: 80,
});
let mut view = View::new(DocumentId::default());
let mut view = View::new(
DocumentId::default(),
vec![GutterType::Diagnostics, GutterType::LineNumbers],
);
view.area = Rect::new(0, 0, 180, 80);
tree.insert(view);

let l0 = tree.focus;
let view = View::new(DocumentId::default());
let view = View::new(
DocumentId::default(),
vec![GutterType::Diagnostics, GutterType::LineNumbers],
);
tree.split(view, Layout::Vertical);
let r0 = tree.focus;

tree.focus = l0;
let view = View::new(DocumentId::default());
let view = View::new(
DocumentId::default(),
vec![GutterType::Diagnostics, GutterType::LineNumbers],
);
tree.split(view, Layout::Horizontal);
let l1 = tree.focus;

tree.focus = l0;
let view = View::new(DocumentId::default());
let view = View::new(
DocumentId::default(),
vec![GutterType::Diagnostics, GutterType::LineNumbers],
);
tree.split(view, Layout::Vertical);
let l2 = tree.focus;

Expand Down
81 changes: 64 additions & 17 deletions helix-view/src/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use helix_core::{
visual_coords_at_pos, Position, RopeSlice, Selection,
};

use std::fmt;

type Jump = (DocumentId, Selection);

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -64,17 +66,11 @@ impl JumpList {
}
}

const GUTTERS: &[(Gutter, usize)] = &[
(gutter::diagnostics_or_breakpoints, 1),
(gutter::line_number, 5),
];

#[derive(Debug)]
pub struct View {
pub id: ViewId,
pub doc: DocumentId,
pub offset: Position,
pub area: Rect,
pub doc: DocumentId,
pub jumps: JumpList,
/// the last accessed file before the current one
pub last_accessed_doc: Option<DocumentId>,
Expand All @@ -85,10 +81,29 @@ pub struct View {
pub last_modified_docs: [Option<DocumentId>; 2],
/// used to store previous selections of tree-sitter objecs
pub object_selections: Vec<Selection>,
pub gutters: Vec<(Gutter, usize)>,
}

impl fmt::Debug for View {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("View")
.field("id", &self.id)
.field("area", &self.area)
.field("doc", &self.doc)
.finish()
}
}

impl View {
pub fn new(doc: DocumentId) -> Self {
pub fn new(doc: DocumentId, gutter_types: Vec<crate::editor::GutterType>) -> Self {
let mut gutters: Vec<(Gutter, usize)> = vec![];
use crate::editor::GutterType;
for gutter_type in &gutter_types {
match gutter_type {
GutterType::Diagnostics => gutters.push((gutter::diagnostics_or_breakpoints, 1)),
GutterType::LineNumbers => gutters.push((gutter::line_numbers, 5)),
}
}
Self {
id: ViewId::default(),
doc,
Expand All @@ -98,17 +113,14 @@ impl View {
last_accessed_doc: None,
last_modified_docs: [None, None],
object_selections: Vec::new(),
gutters,
}
}

pub fn gutters(&self) -> &[(Gutter, usize)] {
GUTTERS
}

pub fn inner_area(&self) -> Rect {
// TODO: cache this
let offset = self
.gutters()
.gutters
.iter()
.map(|(_, width)| *width as u16)
.sum::<u16>()
Expand Down Expand Up @@ -324,11 +336,16 @@ mod tests {
use super::*;
use helix_core::Rope;
const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter
// const OFFSET: u16 = GUTTERS.iter().map(|(_, width)| *width as u16).sum();
const OFFSET_WITHOUT_LINE_NUMBERS: u16 = 2; // 1 diagnostic + 1 gutter
// const OFFSET: u16 = GUTTERS.iter().map(|(_, width)| *width as u16).sum();
use crate::editor::GutterType;

#[test]
fn test_text_pos_at_screen_coords() {
let mut view = View::new(DocumentId::default());
let mut view = View::new(
DocumentId::default(),
vec![GutterType::Diagnostics, GutterType::LineNumbers],
);
view.area = Rect::new(40, 40, 40, 40);
let rope = Rope::from_str("abc\n\tdef");
let text = rope.slice(..);
Expand Down Expand Up @@ -372,9 +389,36 @@ mod tests {
assert_eq!(view.text_pos_at_screen_coords(&text, 41, 80, 4), Some(8));
}

#[test]
fn test_text_pos_at_screen_coords_without_line_numbers_gutter() {
let mut view = View::new(DocumentId::default(), vec![GutterType::Diagnostics]);
view.area = Rect::new(40, 40, 40, 40);
let rope = Rope::from_str("abc\n\tdef");
let text = rope.slice(..);
assert_eq!(
view.text_pos_at_screen_coords(&text, 41, 40 + OFFSET_WITHOUT_LINE_NUMBERS + 1, 4),
Some(4)
);
}

#[test]
fn test_text_pos_at_screen_coords_without_any_gutters() {
let mut view = View::new(DocumentId::default(), vec![]);
view.area = Rect::new(40, 40, 40, 40);
let rope = Rope::from_str("abc\n\tdef");
let text = rope.slice(..);
assert_eq!(
view.text_pos_at_screen_coords(&text, 41, 40 + 1, 4),
Some(4)
);
}

#[test]
fn test_text_pos_at_screen_coords_cjk() {
let mut view = View::new(DocumentId::default());
let mut view = View::new(
DocumentId::default(),
vec![GutterType::Diagnostics, GutterType::LineNumbers],
);
view.area = Rect::new(40, 40, 40, 40);
let rope = Rope::from_str("Hi! こんにちは皆さん");
let text = rope.slice(..);
Expand Down Expand Up @@ -411,7 +455,10 @@ mod tests {

#[test]
fn test_text_pos_at_screen_coords_graphemes() {
let mut view = View::new(DocumentId::default());
let mut view = View::new(
DocumentId::default(),
vec![GutterType::Diagnostics, GutterType::LineNumbers],
);
view.area = Rect::new(40, 40, 40, 40);
let rope = Rope::from_str("Hèl̀l̀ò world!");
let text = rope.slice(..);
Expand Down