mirror of https://github.com/helix-editor/helix
Weave through view_id references so that views into one file have independent selects.
parent
9eaef6e333
commit
6c4093c946
File diff suppressed because it is too large
Load Diff
|
@ -21,6 +21,7 @@ use lsp::CompletionItem;
|
||||||
pub struct Completion {
|
pub struct Completion {
|
||||||
popup: Popup<Menu<CompletionItem>>, // TODO: Popup<Menu> need to be able to access contents.
|
popup: Popup<Menu<CompletionItem>>, // TODO: Popup<Menu> need to be able to access contents.
|
||||||
trigger_offset: usize,
|
trigger_offset: usize,
|
||||||
|
// TODO: maintain a completioncontext with trigger kind & trigger char
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Completion {
|
impl Completion {
|
||||||
|
@ -43,7 +44,9 @@ impl Completion {
|
||||||
// doc.state = snapshot.clone();
|
// doc.state = snapshot.clone();
|
||||||
}
|
}
|
||||||
PromptEvent::Validate => {
|
PromptEvent::Validate => {
|
||||||
let id = editor.view().doc;
|
let view = editor.view();
|
||||||
|
let view_id = view.id;
|
||||||
|
let id = view.doc;
|
||||||
let doc = &mut editor.documents[id];
|
let doc = &mut editor.documents[id];
|
||||||
|
|
||||||
// revert state to what it was before the last update
|
// revert state to what it was before the last update
|
||||||
|
@ -89,18 +92,18 @@ impl Completion {
|
||||||
}
|
}
|
||||||
|
|
||||||
// if more text was entered, remove it
|
// if more text was entered, remove it
|
||||||
let cursor = doc.selection().cursor();
|
let cursor = doc.selection(view_id).cursor();
|
||||||
if trigger_offset < cursor {
|
if trigger_offset < cursor {
|
||||||
let remove = Transaction::change(
|
let remove = Transaction::change(
|
||||||
doc.text(),
|
doc.text(),
|
||||||
vec![(trigger_offset, cursor, None)].into_iter(),
|
vec![(trigger_offset, cursor, None)].into_iter(),
|
||||||
);
|
);
|
||||||
doc.apply(&remove);
|
doc.apply(&remove, view_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
let transaction =
|
let transaction =
|
||||||
util::generate_transaction_from_edits(doc.text(), vec![edit]);
|
util::generate_transaction_from_edits(doc.text(), vec![edit]);
|
||||||
doc.apply(&transaction);
|
doc.apply(&transaction, view_id);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
|
@ -124,15 +127,32 @@ impl Component for Completion {
|
||||||
{
|
{
|
||||||
// recompute menu based on matches
|
// recompute menu based on matches
|
||||||
let menu = self.popup.contents();
|
let menu = self.popup.contents();
|
||||||
let id = cx.editor.view().doc;
|
let view = cx.editor.view();
|
||||||
|
let view_id = view.id;
|
||||||
|
let id = view.doc;
|
||||||
let doc = cx.editor.document(id).unwrap();
|
let doc = cx.editor.document(id).unwrap();
|
||||||
|
|
||||||
let cursor = doc.selection().cursor();
|
// cx.hooks()
|
||||||
|
// cx.add_hook(enum type, ||)
|
||||||
|
// cx.trigger_hook(enum type, &str, ...) <-- there has to be enough to identify doc/view
|
||||||
|
// callback with editor & compositor
|
||||||
|
//
|
||||||
|
// trigger_hook sends event into channel, that's consumed in the global loop and
|
||||||
|
// triggers all registered callbacks
|
||||||
|
// TODO: hooks should get processed immediately so maybe do it after select!(), before
|
||||||
|
// looping?
|
||||||
|
|
||||||
|
let cursor = doc.selection(view_id).cursor();
|
||||||
if self.trigger_offset <= cursor {
|
if self.trigger_offset <= cursor {
|
||||||
let fragment = doc.text().slice(self.trigger_offset..cursor);
|
let fragment = doc.text().slice(self.trigger_offset..cursor);
|
||||||
|
// ^ problem seems to be that we handle events here before the editor layer, so the
|
||||||
|
// keypress isn't included in the editor layer yet...
|
||||||
|
// so we can't use ..= for now.
|
||||||
let text = Cow::from(fragment);
|
let text = Cow::from(fragment);
|
||||||
// TODO: logic is same as ui/picker
|
// TODO: logic is same as ui/picker
|
||||||
menu.score(&text);
|
menu.score(&text);
|
||||||
|
|
||||||
|
// TODO: if after scoring the selection is 0 items, remove popup
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ impl EditorView {
|
||||||
// TODO: this seems to prevent setting style later
|
// TODO: this seems to prevent setting style later
|
||||||
// surface.set_style(viewport, theme.get("ui.background"));
|
// surface.set_style(viewport, theme.get("ui.background"));
|
||||||
|
|
||||||
self.render_diagnostics(&doc, area, surface, theme, is_focused);
|
self.render_diagnostics(&doc, view, area, surface, theme, is_focused);
|
||||||
|
|
||||||
let area = Rect::new(
|
let area = Rect::new(
|
||||||
viewport.x,
|
viewport.x,
|
||||||
|
@ -224,7 +224,7 @@ impl EditorView {
|
||||||
let selection_style = Style::default().bg(Color::Rgb(84, 0, 153));
|
let selection_style = Style::default().bg(Color::Rgb(84, 0, 153));
|
||||||
|
|
||||||
for selection in doc
|
for selection in doc
|
||||||
.selection()
|
.selection(view.id)
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|range| range.overlaps(&screen))
|
.filter(|range| range.overlaps(&screen))
|
||||||
{
|
{
|
||||||
|
@ -332,6 +332,7 @@ impl EditorView {
|
||||||
pub fn render_diagnostics(
|
pub fn render_diagnostics(
|
||||||
&self,
|
&self,
|
||||||
doc: &Document,
|
doc: &Document,
|
||||||
|
view: &View,
|
||||||
viewport: Rect,
|
viewport: Rect,
|
||||||
surface: &mut Surface,
|
surface: &mut Surface,
|
||||||
theme: &Theme,
|
theme: &Theme,
|
||||||
|
@ -344,7 +345,7 @@ impl EditorView {
|
||||||
widgets::{Paragraph, Widget},
|
widgets::{Paragraph, Widget},
|
||||||
};
|
};
|
||||||
|
|
||||||
let cursor = doc.selection().cursor();
|
let cursor = doc.selection(view.id).cursor();
|
||||||
let line = doc.text().char_to_line(cursor);
|
let line = doc.text().char_to_line(cursor);
|
||||||
|
|
||||||
let diagnostics = doc.diagnostics.iter().filter(|diagnostic| {
|
let diagnostics = doc.diagnostics.iter().filter(|diagnostic| {
|
||||||
|
@ -486,11 +487,14 @@ impl Component for EditorView {
|
||||||
EventResult::Consumed(None)
|
EventResult::Consumed(None)
|
||||||
}
|
}
|
||||||
Event::Key(event) => {
|
Event::Key(event) => {
|
||||||
let id = cx.editor.view().doc;
|
let view = cx.editor.view();
|
||||||
|
let view_id = view.id;
|
||||||
|
let id = view.doc;
|
||||||
let mode = cx.editor.document(id).unwrap().mode();
|
let mode = cx.editor.document(id).unwrap().mode();
|
||||||
|
|
||||||
let mut cxt = commands::Context {
|
let mut cxt = commands::Context {
|
||||||
editor: &mut cx.editor,
|
editor: &mut cx.editor,
|
||||||
|
view_id,
|
||||||
count: 1,
|
count: 1,
|
||||||
callback: None,
|
callback: None,
|
||||||
callbacks: cx.callbacks,
|
callbacks: cx.callbacks,
|
||||||
|
|
|
@ -35,7 +35,8 @@ pub fn regex_prompt(
|
||||||
prompt: String,
|
prompt: String,
|
||||||
fun: impl Fn(&mut Document, Regex) + 'static,
|
fun: impl Fn(&mut Document, Regex) + 'static,
|
||||||
) -> Prompt {
|
) -> Prompt {
|
||||||
let snapshot = cx.doc().selection().clone();
|
let view_id = cx.view().id;
|
||||||
|
let snapshot = cx.doc().selection(view_id).clone();
|
||||||
|
|
||||||
Prompt::new(
|
Prompt::new(
|
||||||
prompt,
|
prompt,
|
||||||
|
@ -44,9 +45,11 @@ pub fn regex_prompt(
|
||||||
match event {
|
match event {
|
||||||
PromptEvent::Abort => {
|
PromptEvent::Abort => {
|
||||||
// TODO: also revert text
|
// TODO: also revert text
|
||||||
let id = editor.view().doc;
|
let view = editor.view();
|
||||||
|
let view_id = view.id;
|
||||||
|
let id = view.doc;
|
||||||
let doc = &mut editor.documents[id];
|
let doc = &mut editor.documents[id];
|
||||||
doc.set_selection(snapshot.clone());
|
doc.set_selection(view_id, snapshot.clone());
|
||||||
}
|
}
|
||||||
PromptEvent::Validate => {
|
PromptEvent::Validate => {
|
||||||
// TODO: push_jump to store selection just before jump
|
// TODO: push_jump to store selection just before jump
|
||||||
|
@ -60,16 +63,18 @@ pub fn regex_prompt(
|
||||||
match Regex::new(input) {
|
match Regex::new(input) {
|
||||||
Ok(regex) => {
|
Ok(regex) => {
|
||||||
// let view = &mut editor.view_mut();
|
// let view = &mut editor.view_mut();
|
||||||
let id = editor.view().doc;
|
let view = editor.view();
|
||||||
|
let view_id = view.id;
|
||||||
|
let id = view.doc;
|
||||||
let doc = &mut editor.documents[id];
|
let doc = &mut editor.documents[id];
|
||||||
|
|
||||||
// revert state to what it was before the last update
|
// revert state to what it was before the last update
|
||||||
// TODO: also revert text
|
// TODO: also revert text
|
||||||
doc.set_selection(snapshot.clone());
|
doc.set_selection(view_id, snapshot.clone());
|
||||||
|
|
||||||
fun(doc, regex);
|
fun(doc, regex);
|
||||||
|
|
||||||
editor.ensure_cursor_in_view(editor.view().id);
|
editor.ensure_cursor_in_view(view_id);
|
||||||
}
|
}
|
||||||
Err(_err) => (), // TODO: mark command line as error
|
Err(_err) => (), // TODO: mark command line as error
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,9 @@ use helix_core::{
|
||||||
ChangeSet, Diagnostic, History, Rope, Selection, State, Syntax, Transaction,
|
ChangeSet, Diagnostic, History, Rope, Selection, State, Syntax, Transaction,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::DocumentId;
|
use crate::{DocumentId, ViewId};
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum Mode {
|
pub enum Mode {
|
||||||
|
@ -21,6 +23,7 @@ pub struct Document {
|
||||||
// rope + selection
|
// rope + selection
|
||||||
pub(crate) id: DocumentId,
|
pub(crate) id: DocumentId,
|
||||||
state: State,
|
state: State,
|
||||||
|
pub(crate) selections: HashMap<ViewId, Selection>,
|
||||||
|
|
||||||
path: Option<PathBuf>,
|
path: Option<PathBuf>,
|
||||||
|
|
||||||
|
@ -73,6 +76,7 @@ impl Document {
|
||||||
id: DocumentId::default(),
|
id: DocumentId::default(),
|
||||||
path: None,
|
path: None,
|
||||||
state: State::new(text),
|
state: State::new(text),
|
||||||
|
selections: HashMap::default(),
|
||||||
mode: Mode::Normal,
|
mode: Mode::Normal,
|
||||||
restore_cursor: false,
|
restore_cursor: false,
|
||||||
syntax: None,
|
syntax: None,
|
||||||
|
@ -178,12 +182,12 @@ impl Document {
|
||||||
self.language_server = language_server;
|
self.language_server = language_server;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_selection(&mut self, selection: Selection) {
|
pub fn set_selection(&mut self, view_id: ViewId, selection: Selection) {
|
||||||
// TODO: use a transaction?
|
// TODO: use a transaction?
|
||||||
self.state.selection = selection;
|
self.selections.insert(view_id, selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _apply(&mut self, transaction: &Transaction) -> bool {
|
fn _apply(&mut self, transaction: &Transaction, view_id: ViewId) -> bool {
|
||||||
let old_doc = self.text().clone();
|
let old_doc = self.text().clone();
|
||||||
|
|
||||||
let success = transaction.changes().apply(&mut self.state.doc);
|
let success = transaction.changes().apply(&mut self.state.doc);
|
||||||
|
@ -191,10 +195,11 @@ impl Document {
|
||||||
if !transaction.changes().is_empty() {
|
if !transaction.changes().is_empty() {
|
||||||
// update the selection: either take the selection specified in the transaction, or map the
|
// update the selection: either take the selection specified in the transaction, or map the
|
||||||
// current selection through changes.
|
// current selection through changes.
|
||||||
self.state.selection = transaction
|
let selection = transaction
|
||||||
.selection()
|
.selection()
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or_else(|| self.selection().clone().map(transaction.changes()));
|
.unwrap_or_else(|| self.selection(view_id).clone().map(transaction.changes()));
|
||||||
|
self.set_selection(view_id, selection);
|
||||||
|
|
||||||
self.version += 1;
|
self.version += 1;
|
||||||
|
|
||||||
|
@ -227,14 +232,14 @@ impl Document {
|
||||||
success
|
success
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply(&mut self, transaction: &Transaction) -> bool {
|
pub fn apply(&mut self, transaction: &Transaction, view_id: ViewId) -> bool {
|
||||||
// store the state just before any changes are made. This allows us to undo to the
|
// store the state just before any changes are made. This allows us to undo to the
|
||||||
// state just before a transaction was applied.
|
// state just before a transaction was applied.
|
||||||
if self.changes.is_empty() && !transaction.changes().is_empty() {
|
if self.changes.is_empty() && !transaction.changes().is_empty() {
|
||||||
self.old_state = Some(self.state.clone());
|
self.old_state = Some(self.state.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let success = self._apply(&transaction);
|
let success = self._apply(&transaction, view_id);
|
||||||
|
|
||||||
self.modified = true;
|
self.modified = true;
|
||||||
// TODO: be smarter about modified by keeping track of saved version instead. That way if
|
// TODO: be smarter about modified by keeping track of saved version instead. That way if
|
||||||
|
@ -249,9 +254,9 @@ impl Document {
|
||||||
success
|
success
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn undo(&mut self) -> bool {
|
pub fn undo(&mut self, view_id: ViewId) -> bool {
|
||||||
if let Some(transaction) = self.history.undo() {
|
if let Some(transaction) = self.history.undo() {
|
||||||
let success = self._apply(&transaction);
|
let success = self._apply(&transaction, view_id);
|
||||||
|
|
||||||
// reset changeset to fix len
|
// reset changeset to fix len
|
||||||
self.changes = ChangeSet::new(self.text());
|
self.changes = ChangeSet::new(self.text());
|
||||||
|
@ -261,9 +266,9 @@ impl Document {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn redo(&mut self) -> bool {
|
pub fn redo(&mut self, view_id: ViewId) -> bool {
|
||||||
if let Some(transaction) = self.history.redo() {
|
if let Some(transaction) = self.history.redo() {
|
||||||
let success = self._apply(&transaction);
|
let success = self._apply(&transaction, view_id);
|
||||||
|
|
||||||
// reset changeset to fix len
|
// reset changeset to fix len
|
||||||
self.changes = ChangeSet::new(self.text());
|
self.changes = ChangeSet::new(self.text());
|
||||||
|
@ -273,7 +278,7 @@ impl Document {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn append_changes_to_history(&mut self) {
|
pub fn append_changes_to_history(&mut self, view_id: ViewId) {
|
||||||
if self.changes.is_empty() {
|
if self.changes.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -282,7 +287,8 @@ impl Document {
|
||||||
let changes = std::mem::replace(&mut self.changes, new_changeset);
|
let changes = std::mem::replace(&mut self.changes, new_changeset);
|
||||||
// Instead of doing this messy merge we could always commit, and based on transaction
|
// Instead of doing this messy merge we could always commit, and based on transaction
|
||||||
// annotations either add a new layer or compose into the previous one.
|
// annotations either add a new layer or compose into the previous one.
|
||||||
let transaction = Transaction::from(changes).with_selection(self.selection().clone());
|
let transaction =
|
||||||
|
Transaction::from(changes).with_selection(self.selection(view_id).clone());
|
||||||
|
|
||||||
// HAXX: we need to reconstruct the state as it was before the changes..
|
// HAXX: we need to reconstruct the state as it was before the changes..
|
||||||
let old_state = self.old_state.take().expect("no old_state available");
|
let old_state = self.old_state.take().expect("no old_state available");
|
||||||
|
@ -362,8 +368,8 @@ impl Document {
|
||||||
&self.state.doc
|
&self.state.doc
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn selection(&self) -> &Selection {
|
pub fn selection(&self, view_id: ViewId) -> &Selection {
|
||||||
&self.state.selection
|
&self.selections[&view_id]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn relative_path(&self) -> Option<&Path> {
|
pub fn relative_path(&self) -> Option<&Path> {
|
||||||
|
@ -400,13 +406,14 @@ mod test {
|
||||||
use helix_lsp::{lsp, Client};
|
use helix_lsp::{lsp, Client};
|
||||||
let text = Rope::from("hello");
|
let text = Rope::from("hello");
|
||||||
let mut doc = Document::new(text);
|
let mut doc = Document::new(text);
|
||||||
doc.set_selection(Selection::single(5, 5));
|
let view = ViewId::default();
|
||||||
|
doc.set_selection(view, Selection::single(5, 5));
|
||||||
|
|
||||||
// insert
|
// insert
|
||||||
|
|
||||||
let transaction = Transaction::insert(doc.text(), doc.selection(), " world".into());
|
let transaction = Transaction::insert(doc.text(), doc.selection(view), " world".into());
|
||||||
let old_doc = doc.state.clone();
|
let old_doc = doc.state.clone();
|
||||||
doc.apply(&transaction);
|
doc.apply(&transaction, view);
|
||||||
let changes = Client::changeset_to_changes(&old_doc.doc, doc.text(), transaction.changes());
|
let changes = Client::changeset_to_changes(&old_doc.doc, doc.text(), transaction.changes());
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -425,7 +432,7 @@ mod test {
|
||||||
|
|
||||||
let transaction = transaction.invert(&old_doc.doc);
|
let transaction = transaction.invert(&old_doc.doc);
|
||||||
let old_doc = doc.state.clone();
|
let old_doc = doc.state.clone();
|
||||||
doc.apply(&transaction);
|
doc.apply(&transaction, view);
|
||||||
let changes = Client::changeset_to_changes(&old_doc.doc, doc.text(), transaction.changes());
|
let changes = Client::changeset_to_changes(&old_doc.doc, doc.text(), transaction.changes());
|
||||||
|
|
||||||
// line: 0-based.
|
// line: 0-based.
|
||||||
|
@ -450,13 +457,13 @@ mod test {
|
||||||
|
|
||||||
// also tests that changes are layered, positions depend on previous changes.
|
// also tests that changes are layered, positions depend on previous changes.
|
||||||
|
|
||||||
doc.state.selection = Selection::single(0, 5);
|
doc.set_selection(view, Selection::single(0, 5));
|
||||||
let transaction = Transaction::change(
|
let transaction = Transaction::change(
|
||||||
&doc.state.doc,
|
&doc.state.doc,
|
||||||
vec![(0, 2, Some("aei".into())), (3, 5, Some("ou".into()))].into_iter(),
|
vec![(0, 2, Some("aei".into())), (3, 5, Some("ou".into()))].into_iter(),
|
||||||
);
|
);
|
||||||
// aeilou
|
// aeilou
|
||||||
doc.apply(&transaction);
|
doc.apply(&transaction, view);
|
||||||
let changes =
|
let changes =
|
||||||
Client::changeset_to_changes(&doc.state.doc, doc.text(), transaction.changes());
|
Client::changeset_to_changes(&doc.state.doc, doc.text(), transaction.changes());
|
||||||
|
|
||||||
|
|
|
@ -91,24 +91,40 @@ impl Editor {
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::tree::Layout;
|
use crate::tree::Layout;
|
||||||
|
use helix_core::Selection;
|
||||||
match action {
|
match action {
|
||||||
Action::Replace => {
|
Action::Replace => {
|
||||||
let view = self.view();
|
let view = self.view();
|
||||||
let jump = (view.doc, self.documents[view.doc].selection().clone());
|
let jump = (
|
||||||
|
view.doc,
|
||||||
|
self.documents[view.doc].selection(view.id).clone(),
|
||||||
|
);
|
||||||
|
|
||||||
let view = self.view_mut();
|
let view = self.view_mut();
|
||||||
view.jumps.push(jump);
|
view.jumps.push(jump);
|
||||||
view.doc = id;
|
view.doc = id;
|
||||||
view.first_line = 0;
|
view.first_line = 0;
|
||||||
|
let view_id = view.id;
|
||||||
|
|
||||||
|
// initialize selection for view
|
||||||
|
let doc = &mut self.documents[id];
|
||||||
|
doc.selections.insert(view_id, Selection::point(0));
|
||||||
|
|
||||||
return Ok(id);
|
return Ok(id);
|
||||||
}
|
}
|
||||||
Action::HorizontalSplit => {
|
Action::HorizontalSplit => {
|
||||||
let view = View::new(id)?;
|
let view = View::new(id)?;
|
||||||
self.tree.split(view, Layout::Horizontal);
|
let view_id = self.tree.split(view, Layout::Horizontal);
|
||||||
|
// initialize selection for view
|
||||||
|
let doc = &mut self.documents[id];
|
||||||
|
doc.selections.insert(view_id, Selection::point(0));
|
||||||
}
|
}
|
||||||
Action::VerticalSplit => {
|
Action::VerticalSplit => {
|
||||||
let view = View::new(id)?;
|
let view = View::new(id)?;
|
||||||
self.tree.split(view, Layout::Vertical);
|
let view_id = self.tree.split(view, Layout::Vertical);
|
||||||
|
// initialize selection for view
|
||||||
|
let doc = &mut self.documents[id];
|
||||||
|
doc.selections.insert(view_id, Selection::point(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,6 +150,9 @@ impl Editor {
|
||||||
smol::block_on(language_server.text_document_did_close(doc.identifier())).unwrap();
|
smol::block_on(language_server.text_document_did_close(doc.identifier())).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove selection
|
||||||
|
self.documents[view.doc].selections.remove(&id);
|
||||||
|
|
||||||
// self.documents.remove(view.doc);
|
// self.documents.remove(view.doc);
|
||||||
self.tree.remove(id);
|
self.tree.remove(id);
|
||||||
self._refresh();
|
self._refresh();
|
||||||
|
@ -183,7 +202,7 @@ impl Editor {
|
||||||
const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter
|
const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter
|
||||||
let view = self.view();
|
let view = self.view();
|
||||||
let doc = &self.documents[view.doc];
|
let doc = &self.documents[view.doc];
|
||||||
let cursor = doc.selection().cursor();
|
let cursor = doc.selection(view.id).cursor();
|
||||||
if let Some(mut pos) = view.screen_coords_at_pos(doc, doc.text().slice(..), cursor) {
|
if let Some(mut pos) = view.screen_coords_at_pos(doc, doc.text().slice(..), cursor) {
|
||||||
pos.col += view.area.x as usize + OFFSET as usize;
|
pos.col += view.area.x as usize + OFFSET as usize;
|
||||||
pos.row += view.area.y as usize;
|
pos.row += view.area.y as usize;
|
||||||
|
|
|
@ -74,7 +74,7 @@ impl View {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ensure_cursor_in_view(&mut self, doc: &Document) {
|
pub fn ensure_cursor_in_view(&mut self, doc: &Document) {
|
||||||
let cursor = doc.selection().cursor();
|
let cursor = doc.selection(self.id).cursor();
|
||||||
let line = doc.text().char_to_line(cursor);
|
let line = doc.text().char_to_line(cursor);
|
||||||
let document_end = self.first_line + (self.area.height as usize).saturating_sub(2);
|
let document_end = self.first_line + (self.area.height as usize).saturating_sub(2);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue