diff options
author | Blaž Hrastnik | 2020-10-04 06:40:49 +0000 |
---|---|---|
committer | GitHub | 2020-10-04 06:40:49 +0000 |
commit | 197651eb309e88ba120dcb7a769acac6091483b1 (patch) | |
tree | 46fc50e8d3fb66182e05c4f81acf9c1f9fca479f | |
parent | 7b4a4f6a3cec10f7b2d4a406cc68b5929b36b0a1 (diff) | |
parent | dc11124df54cd4f03d5bfa814e33262643483e87 (diff) |
Merge pull request #2 from helix-editor/tab-implementation
added tab to insert mode
m--------- | helix-syntax/languages/tree-sitter-c-sharp | 0 | ||||
m--------- | helix-syntax/languages/tree-sitter-javascript | 0 | ||||
m--------- | helix-syntax/languages/tree-sitter-toml | 0 | ||||
m--------- | helix-syntax/languages/tree-sitter-typescript | 0 | ||||
-rw-r--r-- | helix-term/src/editor.rs | 21 | ||||
-rw-r--r-- | helix-view/src/commands.rs | 4 | ||||
-rw-r--r-- | helix-view/src/keymap.rs | 4 | ||||
-rw-r--r-- | helix-view/src/view.rs | 52 |
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)) + } } |