helix/helix-view/src/lib.rs

237 lines
7.0 KiB
Rust
Raw Normal View History

#[macro_use]
pub mod macros;
2024-01-30 00:11:00 +08:00
pub mod annotations;
2023-12-01 07:03:26 +08:00
pub mod base64;
pub mod clipboard;
pub mod document;
pub mod editor;
2023-12-01 07:03:26 +08:00
pub mod events;
pub mod expansion;
pub mod graphics;
2021-11-23 11:56:46 +08:00
pub mod gutter;
2023-12-01 07:03:26 +08:00
pub mod handlers;
2021-06-19 23:54:37 +08:00
pub mod info;
pub mod input;
pub mod keyboard;
pub mod register;
pub mod theme;
pub mod tree;
pub mod view;
use std::{borrow::Cow, num::NonZeroUsize, path::Path};
// uses NonZeroUsize so Option<DocumentId> use a byte rather than two
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct DocumentId(NonZeroUsize);
impl Default for DocumentId {
fn default() -> DocumentId {
// Safety: 1 is non-zero
DocumentId(unsafe { NonZeroUsize::new_unchecked(1) })
}
}
impl std::fmt::Display for DocumentId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("{}", self.0))
}
}
slotmap::new_key_type! {
pub struct ViewId;
}
pub enum Align {
Top,
Center,
Bottom,
}
pub fn align_view(doc: &mut Document, view: &View, align: Align) {
rework positioning/rendering and enable softwrap/virtual text (#5420) * rework positioning/rendering, enables softwrap/virtual text This commit is a large rework of the core text positioning and rendering code in helix to remove the assumption that on-screen columns/lines correspond to text columns/lines. A generic `DocFormatter` is introduced that positions graphemes on and is used both for rendering and for movements/scrolling. Both virtual text support (inline, grapheme overlay and multi-line) and a capable softwrap implementation is included. fix picker highlight cleanup doc formatter, use word bondaries for wrapping make visual vertical movement a seperate commnad estimate line gutter width to improve performance cache cursor position cleanup and optimize doc formatter cleanup documentation fix typos Co-authored-by: Daniel Hines <d4hines@gmail.com> update documentation fix panic in last_visual_line funciton improve soft-wrap documentation add extend_visual_line_up/down commands fix non-visual vertical movement streamline virtual text highlighting, add softwrap indicator fix cursor position if softwrap is disabled improve documentation of text_annotations module avoid crashes if view anchor is out of bounds fix: consider horizontal offset when traslation char_idx -> vpos improve default configuration fix: mixed up horizontal and vertical offset reset view position after config reload apply suggestions from review disabled softwrap for very small screens to avoid endless spin fix wrap_indicator setting fix bar cursor disappearring on the EOF character add keybinding for linewise vertical movement fix: inconsistent gutter highlights improve virtual text API make scope idx lookup more ergonomic allow overlapping overlays correctly track char_pos for virtual text adjust configuration deprecate old position fucntions fix infinite loop in highlight lookup fix gutter style fix formatting document max-line-width interaction with softwrap change wrap-indicator example to use empty string fix: rare panic when view is in invalid state (bis) * Apply suggestions from code review Co-authored-by: Michael Davis <mcarsondavis@gmail.com> * improve documentation for positoning functions * simplify tests * fix documentation of Grapheme::width * Apply suggestions from code review Co-authored-by: Michael Davis <mcarsondavis@gmail.com> * add explicit drop invocation * Add explicit MoveFn type alias * add docuntation to Editor::cursor_cache * fix a few typos * explain use of allow(deprecated) * make gj and gk extend in select mode * remove unneded debug and TODO * mark tab_width_at #[inline] * add fast-path to move_vertically_visual in case softwrap is disabled * rename first_line to first_visual_line * simplify duplicate if/else --------- Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2023-02-01 01:03:19 +08:00
let doc_text = doc.text().slice(..);
let cursor = doc.selection(view.id).primary().cursor(doc_text);
let viewport = view.inner_area(doc);
let last_line_height = viewport.height.saturating_sub(1);
let mut view_offset = doc.view_offset(view.id);
let relative = match align {
2022-10-11 01:12:48 +08:00
Align::Center => last_line_height / 2,
Align::Top => 0,
2022-10-11 01:12:48 +08:00
Align::Bottom => last_line_height,
};
rework positioning/rendering and enable softwrap/virtual text (#5420) * rework positioning/rendering, enables softwrap/virtual text This commit is a large rework of the core text positioning and rendering code in helix to remove the assumption that on-screen columns/lines correspond to text columns/lines. A generic `DocFormatter` is introduced that positions graphemes on and is used both for rendering and for movements/scrolling. Both virtual text support (inline, grapheme overlay and multi-line) and a capable softwrap implementation is included. fix picker highlight cleanup doc formatter, use word bondaries for wrapping make visual vertical movement a seperate commnad estimate line gutter width to improve performance cache cursor position cleanup and optimize doc formatter cleanup documentation fix typos Co-authored-by: Daniel Hines <d4hines@gmail.com> update documentation fix panic in last_visual_line funciton improve soft-wrap documentation add extend_visual_line_up/down commands fix non-visual vertical movement streamline virtual text highlighting, add softwrap indicator fix cursor position if softwrap is disabled improve documentation of text_annotations module avoid crashes if view anchor is out of bounds fix: consider horizontal offset when traslation char_idx -> vpos improve default configuration fix: mixed up horizontal and vertical offset reset view position after config reload apply suggestions from review disabled softwrap for very small screens to avoid endless spin fix wrap_indicator setting fix bar cursor disappearring on the EOF character add keybinding for linewise vertical movement fix: inconsistent gutter highlights improve virtual text API make scope idx lookup more ergonomic allow overlapping overlays correctly track char_pos for virtual text adjust configuration deprecate old position fucntions fix infinite loop in highlight lookup fix gutter style fix formatting document max-line-width interaction with softwrap change wrap-indicator example to use empty string fix: rare panic when view is in invalid state (bis) * Apply suggestions from code review Co-authored-by: Michael Davis <mcarsondavis@gmail.com> * improve documentation for positoning functions * simplify tests * fix documentation of Grapheme::width * Apply suggestions from code review Co-authored-by: Michael Davis <mcarsondavis@gmail.com> * add explicit drop invocation * Add explicit MoveFn type alias * add docuntation to Editor::cursor_cache * fix a few typos * explain use of allow(deprecated) * make gj and gk extend in select mode * remove unneded debug and TODO * mark tab_width_at #[inline] * add fast-path to move_vertically_visual in case softwrap is disabled * rename first_line to first_visual_line * simplify duplicate if/else --------- Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2023-02-01 01:03:19 +08:00
let text_fmt = doc.text_format(viewport.width, None);
(view_offset.anchor, view_offset.vertical_offset) = char_idx_at_visual_offset(
rework positioning/rendering and enable softwrap/virtual text (#5420) * rework positioning/rendering, enables softwrap/virtual text This commit is a large rework of the core text positioning and rendering code in helix to remove the assumption that on-screen columns/lines correspond to text columns/lines. A generic `DocFormatter` is introduced that positions graphemes on and is used both for rendering and for movements/scrolling. Both virtual text support (inline, grapheme overlay and multi-line) and a capable softwrap implementation is included. fix picker highlight cleanup doc formatter, use word bondaries for wrapping make visual vertical movement a seperate commnad estimate line gutter width to improve performance cache cursor position cleanup and optimize doc formatter cleanup documentation fix typos Co-authored-by: Daniel Hines <d4hines@gmail.com> update documentation fix panic in last_visual_line funciton improve soft-wrap documentation add extend_visual_line_up/down commands fix non-visual vertical movement streamline virtual text highlighting, add softwrap indicator fix cursor position if softwrap is disabled improve documentation of text_annotations module avoid crashes if view anchor is out of bounds fix: consider horizontal offset when traslation char_idx -> vpos improve default configuration fix: mixed up horizontal and vertical offset reset view position after config reload apply suggestions from review disabled softwrap for very small screens to avoid endless spin fix wrap_indicator setting fix bar cursor disappearring on the EOF character add keybinding for linewise vertical movement fix: inconsistent gutter highlights improve virtual text API make scope idx lookup more ergonomic allow overlapping overlays correctly track char_pos for virtual text adjust configuration deprecate old position fucntions fix infinite loop in highlight lookup fix gutter style fix formatting document max-line-width interaction with softwrap change wrap-indicator example to use empty string fix: rare panic when view is in invalid state (bis) * Apply suggestions from code review Co-authored-by: Michael Davis <mcarsondavis@gmail.com> * improve documentation for positoning functions * simplify tests * fix documentation of Grapheme::width * Apply suggestions from code review Co-authored-by: Michael Davis <mcarsondavis@gmail.com> * add explicit drop invocation * Add explicit MoveFn type alias * add docuntation to Editor::cursor_cache * fix a few typos * explain use of allow(deprecated) * make gj and gk extend in select mode * remove unneded debug and TODO * mark tab_width_at #[inline] * add fast-path to move_vertically_visual in case softwrap is disabled * rename first_line to first_visual_line * simplify duplicate if/else --------- Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2023-02-01 01:03:19 +08:00
doc_text,
cursor,
-(relative as isize),
0,
&text_fmt,
&view.text_annotations(doc, None),
rework positioning/rendering and enable softwrap/virtual text (#5420) * rework positioning/rendering, enables softwrap/virtual text This commit is a large rework of the core text positioning and rendering code in helix to remove the assumption that on-screen columns/lines correspond to text columns/lines. A generic `DocFormatter` is introduced that positions graphemes on and is used both for rendering and for movements/scrolling. Both virtual text support (inline, grapheme overlay and multi-line) and a capable softwrap implementation is included. fix picker highlight cleanup doc formatter, use word bondaries for wrapping make visual vertical movement a seperate commnad estimate line gutter width to improve performance cache cursor position cleanup and optimize doc formatter cleanup documentation fix typos Co-authored-by: Daniel Hines <d4hines@gmail.com> update documentation fix panic in last_visual_line funciton improve soft-wrap documentation add extend_visual_line_up/down commands fix non-visual vertical movement streamline virtual text highlighting, add softwrap indicator fix cursor position if softwrap is disabled improve documentation of text_annotations module avoid crashes if view anchor is out of bounds fix: consider horizontal offset when traslation char_idx -> vpos improve default configuration fix: mixed up horizontal and vertical offset reset view position after config reload apply suggestions from review disabled softwrap for very small screens to avoid endless spin fix wrap_indicator setting fix bar cursor disappearring on the EOF character add keybinding for linewise vertical movement fix: inconsistent gutter highlights improve virtual text API make scope idx lookup more ergonomic allow overlapping overlays correctly track char_pos for virtual text adjust configuration deprecate old position fucntions fix infinite loop in highlight lookup fix gutter style fix formatting document max-line-width interaction with softwrap change wrap-indicator example to use empty string fix: rare panic when view is in invalid state (bis) * Apply suggestions from code review Co-authored-by: Michael Davis <mcarsondavis@gmail.com> * improve documentation for positoning functions * simplify tests * fix documentation of Grapheme::width * Apply suggestions from code review Co-authored-by: Michael Davis <mcarsondavis@gmail.com> * add explicit drop invocation * Add explicit MoveFn type alias * add docuntation to Editor::cursor_cache * fix a few typos * explain use of allow(deprecated) * make gj and gk extend in select mode * remove unneded debug and TODO * mark tab_width_at #[inline] * add fast-path to move_vertically_visual in case softwrap is disabled * rename first_line to first_visual_line * simplify duplicate if/else --------- Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2023-02-01 01:03:19 +08:00
);
doc.set_view_offset(view.id, view_offset);
}
/// Returns the left-side position of the primary selection.
pub fn primary_cursor(view: &View, doc: &Document) -> usize {
doc.selection(view.id)
.primary()
.cursor(doc.text().slice(..))
}
/// Returns the next diagnostic in the document if any.
///
/// This does not wrap-around.
pub fn next_diagnostic_in_doc<'d>(
view: &View,
doc: &'d Document,
severity_filter: Option<helix_core::diagnostic::Severity>,
) -> Option<&'d Diagnostic> {
let cursor = primary_cursor(view, doc);
doc.diagnostics()
.iter()
.filter(|diagnostic| diagnostic.severity >= severity_filter)
.find(|diag| diag.range.start > cursor)
}
/// Returns the previous diagnostic in the document if any.
///
/// This does not wrap-around.
pub fn prev_diagnostic_in_doc<'d>(
view: &View,
doc: &'d Document,
severity_filter: Option<helix_core::diagnostic::Severity>,
) -> Option<&'d Diagnostic> {
let cursor = primary_cursor(view, doc);
doc.diagnostics()
.iter()
.rev()
.filter(|diagnostic| diagnostic.severity >= severity_filter)
.find(|diag| diag.range.start < cursor)
}
pub struct WorkspaceDiagnostic<'e> {
pub path: Cow<'e, Path>,
pub diagnostic: Cow<'e, helix_lsp::lsp::Diagnostic>,
pub offset_encoding: OffsetEncoding,
}
impl<'e> WorkspaceDiagnostic<'e> {
pub fn into_owned(self) -> WorkspaceDiagnostic<'static> {
WorkspaceDiagnostic {
path: Cow::Owned(self.path.into_owned()),
diagnostic: Cow::Owned(self.diagnostic.into_owned()),
offset_encoding: self.offset_encoding,
}
}
}
fn workspace_diagnostics(
editor: &Editor,
severity_filter: Option<helix_core::diagnostic::Severity>,
) -> impl Iterator<Item = WorkspaceDiagnostic<'_>> {
editor
.diagnostics
.iter()
.filter_map(|(uri, diagnostics)| {
// Extract Path from diagnostic Uri, skipping diagnostics that don't have a path.
uri.as_path().map(|p| (p, diagnostics))
})
.flat_map(|(path, diagnostics)| {
let mut diagnostics = diagnostics.iter().collect::<Vec<_>>();
diagnostics.sort_by_key(|(diagnostic, _)| diagnostic.range.start);
diagnostics
.into_iter()
.map(move |(diagnostic, diagnostic_provider)| {
(path, diagnostic, diagnostic_provider)
})
})
.filter(move |(_, diagnostic, _)| {
// Filter by severity
let severity = diagnostic
.severity
.and_then(Document::lsp_severity_to_severity);
severity >= severity_filter
})
.map(|(path, diag, diagnostic_provider)| {
match diagnostic_provider {
DiagnosticProvider::Lsp { server_id, .. } => {
// Map language server ID to offset encoding
let offset_encoding = editor
.language_server_by_id(*server_id)
.map(|client| client.offset_encoding())
.unwrap_or_default();
(path, diag, offset_encoding)
}
}
})
.map(|(path, diagnostic, offset_encoding)| WorkspaceDiagnostic {
path: Cow::Borrowed(path),
diagnostic: Cow::Borrowed(diagnostic),
offset_encoding,
})
}
pub fn first_diagnostic_in_workspace(
editor: &Editor,
severity_filter: Option<helix_core::diagnostic::Severity>,
) -> Option<WorkspaceDiagnostic> {
workspace_diagnostics(editor, severity_filter).next()
}
pub fn next_diagnostic_in_workspace(
editor: &Editor,
severity_filter: Option<helix_core::diagnostic::Severity>,
) -> Option<WorkspaceDiagnostic> {
let (view, doc) = current_ref!(editor);
let Some(current_doc_path) = doc.path() else {
return first_diagnostic_in_workspace(editor, severity_filter);
};
let cursor = primary_cursor(view, doc);
#[allow(clippy::filter_next)]
workspace_diagnostics(editor, severity_filter)
.filter(|d| {
// Skip diagnostics before the current document
d.path >= current_doc_path.as_path()
})
.filter(|d| {
// Skip diagnostics before the primary cursor in the current document
if d.path == current_doc_path.as_path() {
let Some(start) = helix_lsp::util::lsp_pos_to_pos(
doc.text(),
d.diagnostic.range.start,
d.offset_encoding,
) else {
return false;
};
if start <= cursor {
return false;
}
}
true
})
.next()
}
pub fn ensure_selections_forward(view: &View, doc: &mut Document) {
let selection = doc
.selection(view.id)
.clone()
.transform(|r| r.with_direction(Direction::Forward));
doc.set_selection(view.id, selection);
}
pub use document::Document;
pub use editor::Editor;
use helix_core::{
char_idx_at_visual_offset, diagnostic::DiagnosticProvider, movement::Direction, Diagnostic,
};
use helix_lsp::OffsetEncoding;
pub use theme::Theme;
pub use view::View;