mirror of https://github.com/helix-editor/helix
feat: functional gutter
parent
fdd36d6261
commit
627885ddeb
|
@ -2677,12 +2677,14 @@ fn global_search(cx: &mut Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut matches: HashMap<PathBuf, Vec<(usize, String)>> = HashMap::new();
|
let mut matches: HashMap<PathBuf, Vec<(usize, String)>> = HashMap::new();
|
||||||
|
let mut lines: Vec<(PathBuf, usize)> = vec![];
|
||||||
|
|
||||||
for result in results {
|
for result in results {
|
||||||
let path = result.path.clone();
|
let path = result.path.clone();
|
||||||
let line = result.line_num;
|
let line = result.line_num;
|
||||||
let text = result.line_content.clone();
|
let text = result.line_content.clone();
|
||||||
|
|
||||||
|
lines.push((path.clone(), line));
|
||||||
matches.entry(path).or_default().push((line, text));
|
matches.entry(path).or_default().push((line, text));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2703,6 +2705,7 @@ fn global_search(cx: &mut Context) {
|
||||||
doc_text,
|
doc_text,
|
||||||
matches,
|
matches,
|
||||||
line_map,
|
line_map,
|
||||||
|
lines,
|
||||||
// TODO: actually learn how to detect encoding
|
// TODO: actually learn how to detect encoding
|
||||||
None,
|
None,
|
||||||
cx.editor.config.clone(),
|
cx.editor.config.clone(),
|
||||||
|
@ -2725,7 +2728,9 @@ fn global_refactor(cx: &mut Context) {
|
||||||
|
|
||||||
match &document_type {
|
match &document_type {
|
||||||
helix_view::document::DocumentType::File => return,
|
helix_view::document::DocumentType::File => return,
|
||||||
helix_view::document::DocumentType::Refactor { matches, line_map } => {
|
helix_view::document::DocumentType::Refactor {
|
||||||
|
matches, line_map, ..
|
||||||
|
} => {
|
||||||
let line_ending: LineEnding = cx.editor.config.load().default_line_ending.into();
|
let line_ending: LineEnding = cx.editor.config.load().default_line_ending.into();
|
||||||
let refactor_id = doc!(cx.editor).id();
|
let refactor_id = doc!(cx.editor).id();
|
||||||
let replace_text = doc!(cx.editor).text().clone();
|
let replace_text = doc!(cx.editor).text().clone();
|
||||||
|
@ -3276,7 +3281,8 @@ fn buffer_picker(cx: &mut Context) {
|
||||||
&doc.document_type,
|
&doc.document_type,
|
||||||
helix_view::document::DocumentType::Refactor {
|
helix_view::document::DocumentType::Refactor {
|
||||||
matches: _,
|
matches: _,
|
||||||
line_map: _
|
line_map: _,
|
||||||
|
lines: _,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
|
@ -594,6 +594,7 @@ impl EditorView {
|
||||||
helix_view::document::DocumentType::Refactor {
|
helix_view::document::DocumentType::Refactor {
|
||||||
matches: _,
|
matches: _,
|
||||||
line_map: _,
|
line_map: _,
|
||||||
|
lines: _,
|
||||||
} => helix_view::document::REFACTOR_BUFFER_NAME,
|
} => helix_view::document::REFACTOR_BUFFER_NAME,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -462,6 +462,7 @@ where
|
||||||
helix_view::document::DocumentType::Refactor {
|
helix_view::document::DocumentType::Refactor {
|
||||||
matches: _,
|
matches: _,
|
||||||
line_map: _,
|
line_map: _,
|
||||||
|
lines: _,
|
||||||
} => REFACTOR_BUFFER_NAME.into(),
|
} => REFACTOR_BUFFER_NAME.into(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -144,8 +144,12 @@ pub enum DocumentOpenError {
|
||||||
pub enum DocumentType {
|
pub enum DocumentType {
|
||||||
File,
|
File,
|
||||||
Refactor {
|
Refactor {
|
||||||
|
// Filepath: list of (line_num, text)
|
||||||
matches: HashMap<PathBuf, Vec<(usize, String)>>,
|
matches: HashMap<PathBuf, Vec<(usize, String)>>,
|
||||||
|
// (Filepath, line_num): line_num (in buffer)
|
||||||
line_map: HashMap<(PathBuf, usize), usize>,
|
line_map: HashMap<(PathBuf, usize), usize>,
|
||||||
|
// List of (line_num, Filepath) in buffer order
|
||||||
|
lines: Vec<(PathBuf, usize)>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -748,6 +752,7 @@ impl Document {
|
||||||
text: Rope,
|
text: Rope,
|
||||||
matches: HashMap<PathBuf, Vec<(usize, String)>>,
|
matches: HashMap<PathBuf, Vec<(usize, String)>>,
|
||||||
line_map: HashMap<(PathBuf, usize), usize>,
|
line_map: HashMap<(PathBuf, usize), usize>,
|
||||||
|
lines: Vec<(PathBuf, usize)>,
|
||||||
encoding_with_bom_info: Option<(&'static Encoding, bool)>,
|
encoding_with_bom_info: Option<(&'static Encoding, bool)>,
|
||||||
config: Arc<dyn DynAccess<Config>>,
|
config: Arc<dyn DynAccess<Config>>,
|
||||||
syn_loader: Arc<ArcSwap<syntax::Loader>>,
|
syn_loader: Arc<ArcSwap<syntax::Loader>>,
|
||||||
|
@ -794,7 +799,11 @@ impl Document {
|
||||||
color_swatches: None,
|
color_swatches: None,
|
||||||
color_swatch_controller: TaskController::new(),
|
color_swatch_controller: TaskController::new(),
|
||||||
syn_loader,
|
syn_loader,
|
||||||
document_type: DocumentType::Refactor { matches, line_map },
|
document_type: DocumentType::Refactor {
|
||||||
|
matches,
|
||||||
|
line_map,
|
||||||
|
lines,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1813,6 +1822,7 @@ impl Document {
|
||||||
DocumentType::Refactor {
|
DocumentType::Refactor {
|
||||||
matches: _,
|
matches: _,
|
||||||
line_map: _,
|
line_map: _,
|
||||||
|
lines: _,
|
||||||
} => false,
|
} => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ use std::fmt::Write;
|
||||||
|
|
||||||
use helix_core::syntax::config::LanguageServerFeature;
|
use helix_core::syntax::config::LanguageServerFeature;
|
||||||
|
|
||||||
|
use crate::document::DocumentType;
|
||||||
use crate::{
|
use crate::{
|
||||||
editor::GutterType,
|
editor::GutterType,
|
||||||
graphics::{Style, UnderlineStyle},
|
graphics::{Style, UnderlineStyle},
|
||||||
|
@ -16,6 +17,8 @@ pub type GutterFn<'doc> = Box<dyn FnMut(usize, bool, bool, &mut String) -> Optio
|
||||||
pub type Gutter =
|
pub type Gutter =
|
||||||
for<'doc> fn(&'doc Editor, &'doc Document, &View, &Theme, bool, usize) -> GutterFn<'doc>;
|
for<'doc> fn(&'doc Editor, &'doc Document, &View, &Theme, bool, usize) -> GutterFn<'doc>;
|
||||||
|
|
||||||
|
const REFACTOR_GUTTER_WIDTH: usize = 20;
|
||||||
|
|
||||||
impl GutterType {
|
impl GutterType {
|
||||||
pub fn style<'doc>(
|
pub fn style<'doc>(
|
||||||
self,
|
self,
|
||||||
|
@ -151,10 +154,6 @@ pub fn line_numbers<'doc>(
|
||||||
|
|
||||||
let last_line_in_view = view.estimate_last_doc_line(doc);
|
let last_line_in_view = view.estimate_last_doc_line(doc);
|
||||||
|
|
||||||
// Whether to draw the line number for the last line of the
|
|
||||||
// document or not. We only draw it if it's not an empty line.
|
|
||||||
let draw_last = text.line_to_byte(last_line_in_view) < text.len_bytes();
|
|
||||||
|
|
||||||
let linenr = theme.get("ui.linenr");
|
let linenr = theme.get("ui.linenr");
|
||||||
let linenr_select = theme.get("ui.linenr.selected");
|
let linenr_select = theme.get("ui.linenr.selected");
|
||||||
|
|
||||||
|
@ -163,10 +162,14 @@ pub fn line_numbers<'doc>(
|
||||||
.char_to_line(doc.selection(view.id).primary().cursor(text));
|
.char_to_line(doc.selection(view.id).primary().cursor(text));
|
||||||
|
|
||||||
let line_number = editor.config().line_number;
|
let line_number = editor.config().line_number;
|
||||||
let mode = editor.mode;
|
let draw_last = text.line_to_byte(last_line_in_view) < text.len_bytes();
|
||||||
|
|
||||||
Box::new(
|
match &doc.document_type {
|
||||||
|
DocumentType::File => Box::new(
|
||||||
move |line: usize, selected: bool, first_visual_line: bool, out: &mut String| {
|
move |line: usize, selected: bool, first_visual_line: bool, out: &mut String| {
|
||||||
|
// Whether to draw the line number for the last line of the
|
||||||
|
// document or not. We only draw it if it's not an empty line.
|
||||||
|
let mode = editor.mode;
|
||||||
if line == last_line_in_view && !draw_last {
|
if line == last_line_in_view && !draw_last {
|
||||||
write!(out, "{:>1$}", '~', width).unwrap();
|
write!(out, "{:>1$}", '~', width).unwrap();
|
||||||
Some(linenr)
|
Some(linenr)
|
||||||
|
@ -199,7 +202,53 @@ pub fn line_numbers<'doc>(
|
||||||
first_visual_line.then_some(style)
|
first_visual_line.then_some(style)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
),
|
||||||
|
DocumentType::Refactor {
|
||||||
|
matches: _,
|
||||||
|
line_map: _,
|
||||||
|
lines,
|
||||||
|
} => Box::new(
|
||||||
|
move |line: usize, selected: bool, first_visual_line: bool, out: &mut String| {
|
||||||
|
if let Some((file_path, line_num)) = lines.get(line) {
|
||||||
|
let gutter = format_path_line(
|
||||||
|
file_path.to_str().unwrap_or("<invalid path>"),
|
||||||
|
line_num + 1,
|
||||||
|
REFACTOR_GUTTER_WIDTH,
|
||||||
|
);
|
||||||
|
write!(out, "{}", gutter).unwrap();
|
||||||
|
} else {
|
||||||
|
write!(out, "{:>1$}", '~', REFACTOR_GUTTER_WIDTH).unwrap();
|
||||||
|
}
|
||||||
|
let style = if selected && is_focused {
|
||||||
|
linenr_select
|
||||||
|
} else {
|
||||||
|
linenr
|
||||||
|
};
|
||||||
|
// Some(style)
|
||||||
|
first_visual_line.then_some(style)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_path_line(path: &str, line: usize, max_width: usize) -> String {
|
||||||
|
let raw = format!("{path}:{line}");
|
||||||
|
|
||||||
|
if raw.len() <= max_width {
|
||||||
|
format!("{:>width$}", raw, width = max_width)
|
||||||
|
} else {
|
||||||
|
let ellipsis = "...";
|
||||||
|
let keep = max_width.saturating_sub(ellipsis.len());
|
||||||
|
let tail = raw
|
||||||
|
.chars()
|
||||||
|
.rev()
|
||||||
|
.take(keep)
|
||||||
|
.collect::<String>()
|
||||||
|
.chars()
|
||||||
|
.rev()
|
||||||
|
.collect::<String>();
|
||||||
|
format!("{:>width$}", format!("{ellipsis}{tail}"), width = max_width)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The width of a "line-numbers" gutter
|
/// The width of a "line-numbers" gutter
|
||||||
|
@ -208,6 +257,9 @@ pub fn line_numbers<'doc>(
|
||||||
/// whether there is content on the last line (the `~` line), and the
|
/// whether there is content on the last line (the `~` line), and the
|
||||||
/// `editor.gutters.line-numbers.min-width` settings.
|
/// `editor.gutters.line-numbers.min-width` settings.
|
||||||
fn line_numbers_width(view: &View, doc: &Document) -> usize {
|
fn line_numbers_width(view: &View, doc: &Document) -> usize {
|
||||||
|
if matches!(doc.document_type, DocumentType::Refactor { .. }) {
|
||||||
|
return REFACTOR_GUTTER_WIDTH;
|
||||||
|
}
|
||||||
let text = doc.text();
|
let text = doc.text();
|
||||||
let last_line = text.len_lines().saturating_sub(1);
|
let last_line = text.len_lines().saturating_sub(1);
|
||||||
let draw_last = text.line_to_byte(last_line) < text.len_bytes();
|
let draw_last = text.line_to_byte(last_line) < text.len_bytes();
|
||||||
|
|
Loading…
Reference in New Issue