summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
m---------helix-syntax/languages/tree-sitter-c-sharp0
m---------helix-syntax/languages/tree-sitter-javascript0
m---------helix-syntax/languages/tree-sitter-toml0
m---------helix-syntax/languages/tree-sitter-typescript0
-rw-r--r--helix-term/src/editor.rs21
-rw-r--r--helix-view/src/commands.rs4
-rw-r--r--helix-view/src/keymap.rs4
-rw-r--r--helix-view/src/view.rs52
8 files changed, 71 insertions, 10 deletions
diff --git a/helix-syntax/languages/tree-sitter-c-sharp b/helix-syntax/languages/tree-sitter-c-sharp
-Subproject 47cde3884c0b52307ca032317bed3dc06185a04
+Subproject 1349bbfd7e84655abdf94d320c115ba754fda53
diff --git a/helix-syntax/languages/tree-sitter-javascript b/helix-syntax/languages/tree-sitter-javascript
-Subproject 3d5493495b62b4ff8e8c24aee7519dd904e2581
+Subproject c4f5c8f657b03be92eada845e9ebbf869fb4b4d
diff --git a/helix-syntax/languages/tree-sitter-toml b/helix-syntax/languages/tree-sitter-toml
-Subproject 42c9ff20c0371bed7f514036e823f10793caace
+Subproject e1aa4dd51bfa83fbde26565e0b80f5ed17b0bdc
diff --git a/helix-syntax/languages/tree-sitter-typescript b/helix-syntax/languages/tree-sitter-typescript
-Subproject 07a12bdf024d66d267bd7f96870f8bbbaceaa5d
+Subproject 767165ad527cbe98d513c7eb16161d1251bfd4e
diff --git a/helix-term/src/editor.rs b/helix-term/src/editor.rs
index a3bc8b3b..4386834a 100644
--- a/helix-term/src/editor.rs
+++ b/helix-term/src/editor.rs
@@ -1,5 +1,5 @@
use clap::ArgMatches as Args;
-use helix_core::{state::coords_at_pos, state::Mode, syntax::HighlightEvent, Range, State};
+use helix_core::{state::Mode, syntax::HighlightEvent, Range, State};
use helix_view::{commands, keymap, View};
use std::{
@@ -24,6 +24,8 @@ use crossterm::{
use tui::{backend::CrosstermBackend, buffer::Buffer as Surface, layout::Rect, style::Style};
+const TAB_WIDTH: usize = 4;
+
type Terminal = tui::Terminal<CrosstermBackend<std::io::Stdout>>;
static EX: smol::Executor = smol::Executor::new();
@@ -85,10 +87,7 @@ impl Editor {
// TODO: inefficient, should feed chunks.iter() to tree_sitter.parse_with(|offset, pos|)
let source_code = view.state.doc().to_string();
- let last_line = std::cmp::min(
- (view.first_line + viewport.height - 1) as usize,
- view.state.doc().len_lines() - 1,
- );
+ let last_line = view.last_line(viewport);
let range = {
// calculate viewport byte ranges
@@ -172,6 +171,8 @@ impl Editor {
if line >= viewport.height {
break 'outer;
}
+ } else if grapheme == "\t" {
+ visual_x += (TAB_WIDTH as u16);
} else {
// Cow will prevent allocations if span contained in a single slice
// which should really be the majority case
@@ -281,12 +282,16 @@ impl Editor {
// render the cursor
let pos = view.state.selection().cursor();
- let coords = coords_at_pos(&view.state.doc().slice(..), pos);
+
+ let pos = view
+ .screen_coords_at_pos(&view.state.doc().slice(..), pos, area)
+ .expect("Cursor is out of bounds.");
+
execute!(
stdout,
cursor::MoveTo(
- coords.col as u16 + viewport.x,
- coords.row as u16 - view.first_line + viewport.y,
+ pos.col as u16 + viewport.x,
+ pos.row as u16 - view.first_line + viewport.y,
)
);
}
diff --git a/helix-view/src/commands.rs b/helix-view/src/commands.rs
index 1fb9c90e..6dd1101c 100644
--- a/helix-view/src/commands.rs
+++ b/helix-view/src/commands.rs
@@ -301,6 +301,10 @@ pub fn insert_char(view: &mut View, c: char) {
// TODO: need to store into history if successful
}
+pub fn insert_tab(view: &mut View, _count: usize) {
+ insert_char(view, '\t');
+}
+
pub fn insert_newline(view: &mut View, _count: usize) {
insert_char(view, '\n');
}
diff --git a/helix-view/src/keymap.rs b/helix-view/src/keymap.rs
index d4ab85a2..ef23ff2a 100644
--- a/helix-view/src/keymap.rs
+++ b/helix-view/src/keymap.rs
@@ -157,6 +157,10 @@ pub fn default() -> Keymaps {
code: KeyCode::Enter,
modifiers: Modifiers::NONE
}] => commands::insert_newline,
+ vec![Key {
+ code: KeyCode::Tab,
+ modifiers: Modifiers::NONE
+ }] => commands::insert_tab,
)
)
}
diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs
index d96752d0..ac342d61 100644
--- a/helix-view/src/view.rs
+++ b/helix-view/src/view.rs
@@ -1,9 +1,13 @@
use anyhow::Error;
-use std::path::PathBuf;
+use std::{borrow::Cow, path::PathBuf};
use crate::theme::Theme;
-use helix_core::State;
+use helix_core::{
+ graphemes::{grapheme_width, RopeGraphemes},
+ Position, RopeSlice, State,
+};
+use tui::layout::Rect;
pub struct View {
pub state: State,
@@ -44,4 +48,48 @@ impl View {
self.first_line = line.saturating_sub(padding);
}
}
+
+ /// Calculates the last visible line on screen
+ #[inline]
+ pub fn last_line(&self, viewport: Rect) -> usize {
+ std::cmp::min(
+ (self.first_line + viewport.height - 1) as usize,
+ self.state.doc().len_lines() - 1,
+ )
+ }
+
+ /// Translates a document position to an absolute position in the terminal.
+ /// Returns a (line, col) position if the position is visible on screen.
+ // TODO: Could return width as well for the character width at cursor.
+ pub fn screen_coords_at_pos(
+ &self,
+ text: &RopeSlice,
+ pos: usize,
+ viewport: Rect,
+ ) -> Option<Position> {
+ let line = text.char_to_line(pos);
+
+ if line < self.first_line as usize || line > self.last_line(viewport) {
+ // Line is not visible on screen
+ return None;
+ }
+
+ let line_start = text.line_to_char(line);
+ let line_slice = text.slice(line_start..pos);
+ let mut col = 0;
+
+ for grapheme in RopeGraphemes::new(&line_slice) {
+ if grapheme == "\t" {
+ // TODO: this should be const TAB_WIDTH
+ col += 4;
+ } else {
+ let grapheme = Cow::from(grapheme);
+ col += grapheme_width(&grapheme);
+ }
+ }
+
+ let row = line - self.first_line as usize;
+
+ Some(Position::new(row, col))
+ }
}