Ver código fonte

worksapce模式,支持查看工作区内容,动态打开工作区文件等操作 (#33)

GnoCiYeH 5 meses atrás
pai
commit
0d50babc60

+ 5 - 0
src/application/handler/app.rs

@@ -16,3 +16,8 @@ pub fn to_normal_mode(app: &mut Application) -> Result<()> {
     app.switch_mode(ModeKey::Normal);
     app.switch_mode(ModeKey::Normal);
     Ok(())
     Ok(())
 }
 }
+
+pub fn to_workspace_mode(app: &mut Application) -> Result<()> {
+    app.switch_mode(ModeKey::Workspace);
+    Ok(())
+}

+ 32 - 0
src/application/handler/workspace.rs

@@ -1,3 +1,4 @@
+use crate::application::mode::{ModeData, ModeKey};
 use crate::application::Application;
 use crate::application::Application;
 use crate::errors::*;
 use crate::errors::*;
 
 
@@ -14,3 +15,34 @@ pub fn undo(app: &mut Application) -> Result<()> {
     }
     }
     Ok(())
     Ok(())
 }
 }
+
+pub fn to_normal_mode(app: &mut Application) -> Result<()> {
+    if let ModeData::Workspace(ref mode) = app.mode {
+        app.workspace.select_buffer(mode.prev_buffer_id);
+    }
+    app.switch_mode(ModeKey::Normal);
+    Ok(())
+}
+
+pub fn move_down(app: &mut Application) -> Result<()> {
+    if let ModeData::Workspace(ref mut mode) = app.mode {
+        mode.move_down();
+    }
+    Ok(())
+}
+
+pub fn move_up(app: &mut Application) -> Result<()> {
+    if let ModeData::Workspace(ref mut mode) = app.mode {
+        mode.move_up();
+    }
+    Ok(())
+}
+
+pub fn enter(app: &mut Application) -> Result<()> {
+    if let ModeData::Workspace(ref mut mode) = app.mode {
+        if mode.open(&mut app.workspace, &mut app.monitor)? {
+            to_normal_mode(app)?;
+        }
+    }
+    Ok(())
+}

+ 18 - 23
src/application/mod.rs

@@ -1,30 +1,16 @@
-use crate::{
-    errors::*,
-    modules::input::{InputLoader, InputMapper},
-    utils::ui::AppInternalInfomation,
-};
-use app_dirs2::AppInfo;
-use crossterm::{
-    event::{Event, KeyCode, KeyEvent, ModifierKeyCode},
-    terminal::{disable_raw_mode, enable_raw_mode},
+use crate::errors::*;
+use crate::modules::input::{InputLoader, InputMapper};
+use crossterm::{event::Event, terminal::disable_raw_mode};
+use mode::{
+    error::ErrorRenderer, workspace::WorkspaceModeData, ModeData, ModeKey, ModeRenderer, ModeRouter,
 };
 };
-use mode::{error::ErrorRenderer, ModeData, ModeKey, ModeRenderer, ModeRouter};
 use smallvec::SmallVec;
 use smallvec::SmallVec;
 
 
-use std::{
-    cell::RefCell,
-    collections::HashMap,
-    io::{self, Read},
-    mem,
-    path::{Path, PathBuf},
-    rc::Rc,
-    sync::Arc,
-};
+use std::{cell::RefCell, collections::HashMap, mem, rc::Rc, sync::Arc};
 
 
 use crate::{
 use crate::{
     config::appconfig::AppSetting,
     config::appconfig::AppSetting,
     modules::perferences::{Perferences, PerferencesManager},
     modules::perferences::{Perferences, PerferencesManager},
-    plugin::system::PluginSystem,
     utils::{file::FileManager, ui::uicore::Ui},
     utils::{file::FileManager, ui::uicore::Ui},
     view::monitor::Monitor,
     view::monitor::Monitor,
     workspace::Workspace,
     workspace::Workspace,
@@ -84,11 +70,11 @@ impl Application {
         })
         })
     }
     }
 
 
-    fn init(&mut self) -> io::Result<()> {
+    fn init(&mut self) -> Result<()> {
         // Ui::init_ui()?;
         // Ui::init_ui()?;
         // PluginSystem::init_system();
         // PluginSystem::init_system();
         // self.monitor.terminal.clear().unwrap();
         // self.monitor.terminal.clear().unwrap();
-        self.init_modes();
+        self.init_modes()?;
         // if !self.bak {
         // if !self.bak {
         //     self.ui.start_page_ui()?;
         //     self.ui.start_page_ui()?;
         // }
         // }
@@ -96,12 +82,21 @@ impl Application {
         Ok(())
         Ok(())
     }
     }
 
 
-    fn init_modes(&mut self) {
+    fn init_modes(&mut self) -> Result<()> {
         self.mode_history.insert(ModeKey::Normal, ModeData::Normal);
         self.mode_history.insert(ModeKey::Normal, ModeData::Normal);
         self.mode_history.insert(ModeKey::Insert, ModeData::Insert);
         self.mode_history.insert(ModeKey::Insert, ModeData::Insert);
         self.mode_history
         self.mode_history
             .insert(ModeKey::Error, ModeData::Error(Error::default()));
             .insert(ModeKey::Error, ModeData::Error(Error::default()));
         self.mode_history.insert(ModeKey::Exit, ModeData::Exit);
         self.mode_history.insert(ModeKey::Exit, ModeData::Exit);
+        self.mode_history.insert(
+            ModeKey::Workspace,
+            ModeData::Workspace(WorkspaceModeData::new(
+                &mut self.workspace,
+                &mut self.monitor,
+            )?),
+        );
+
+        Ok(())
     }
     }
 
 
     pub fn run(&mut self) -> Result<()> {
     pub fn run(&mut self) -> Result<()> {

+ 6 - 1
src/application/mode/mod.rs

@@ -9,6 +9,7 @@ use linked_hash_map::LinkedHashMap;
 use normal::NormalRenderer;
 use normal::NormalRenderer;
 use smallvec::SmallVec;
 use smallvec::SmallVec;
 use strum::EnumIter;
 use strum::EnumIter;
+use workspace::{WorkspaceModeData, WorkspaceRender};
 use yaml_rust::Yaml;
 use yaml_rust::Yaml;
 
 
 use super::handler::handle_map;
 use super::handler::handle_map;
@@ -17,13 +18,14 @@ use super::Application;
 pub mod error;
 pub mod error;
 mod insert;
 mod insert;
 mod normal;
 mod normal;
+pub mod workspace;
 
 
-#[derive(Debug)]
 pub enum ModeData {
 pub enum ModeData {
     Normal,
     Normal,
     Error(Error),
     Error(Error),
     Exit,
     Exit,
     Insert,
     Insert,
+    Workspace(WorkspaceModeData),
     // Other(OtherData)
     // Other(OtherData)
 }
 }
 
 
@@ -33,6 +35,7 @@ pub enum ModeKey {
     Error,
     Error,
     Exit,
     Exit,
     Insert,
     Insert,
+    Workspace,
 }
 }
 
 
 impl ModeKey {
 impl ModeKey {
@@ -40,6 +43,7 @@ impl ModeKey {
         match self {
         match self {
             ModeKey::Normal => Some("normal".into()),
             ModeKey::Normal => Some("normal".into()),
             ModeKey::Insert => Some("insert".into()),
             ModeKey::Insert => Some("insert".into()),
+            ModeKey::Workspace => Some("workspace".into()),
             _ => None,
             _ => None,
         }
         }
     }
     }
@@ -135,6 +139,7 @@ impl ModeRenderer for ModeRouter {
             ModeData::Normal => NormalRenderer::render(workspace, monitor, mode),
             ModeData::Normal => NormalRenderer::render(workspace, monitor, mode),
             ModeData::Error(_) => ErrorRenderer::render(workspace, monitor, mode),
             ModeData::Error(_) => ErrorRenderer::render(workspace, monitor, mode),
             ModeData::Insert => InsertRenderer::render(workspace, monitor, mode),
             ModeData::Insert => InsertRenderer::render(workspace, monitor, mode),
+            ModeData::Workspace(_) => WorkspaceRender::render(workspace, monitor, mode),
             ModeData::Exit => todo!(),
             ModeData::Exit => todo!(),
         }
         }
     }
     }

+ 1 - 0
src/application/mode/normal.rs

@@ -18,6 +18,7 @@ impl ModeRenderer for NormalRenderer {
         let mut presenter = monitor.build_presenter()?;
         let mut presenter = monitor.build_presenter()?;
 
 
         if let Some(buffer) = &workspace.current_buffer {
         if let Some(buffer) = &workspace.current_buffer {
+            warn!("normal buffer id: {}", buffer.id.unwrap());
             let data = buffer.data();
             let data = buffer.data();
             presenter.print_buffer(buffer, &data, &workspace.syntax_set, None, None)?;
             presenter.print_buffer(buffer, &data, &workspace.syntax_set, None, None)?;
 
 

+ 315 - 0
src/application/mode/workspace.rs

@@ -0,0 +1,315 @@
+use std::{collections::HashSet, os::unix::fs::MetadataExt, path::PathBuf};
+
+use crossterm::style::Color;
+use error_chain::bail;
+use unicode_segmentation::UnicodeSegmentation;
+use walkdir::{DirEntry, DirEntryExt, WalkDir};
+
+use super::{ModeData, ModeRenderer};
+use crate::{
+    buffer::Buffer,
+    errors::*,
+    util::{position::Position, range::Range},
+    view::{
+        colors::colors::Colors, monitor::Monitor, status_data::StatusLineData, style::CharStyle,
+    },
+    workspace::Workspace,
+};
+pub struct WorkspaceModeData {
+    path: PathBuf,
+    selected_index: usize,
+    selected_path: PathBuf,
+    current_render_index: usize,
+    max_index: usize,
+    opened_dir_inos: HashSet<u64>,
+    buffer_id: usize,
+    pub prev_buffer_id: usize,
+    highlight_ranges: Vec<(Range, CharStyle, Colors)>,
+}
+
+impl WorkspaceModeData {
+    pub fn new(workspace: &mut Workspace, monitor: &mut Monitor) -> Result<WorkspaceModeData> {
+        if !workspace.path.is_dir() {
+            bail!("The workspace must be a directory!");
+        }
+
+        let mut opened_dir_inos = HashSet::new();
+        opened_dir_inos.insert(workspace.path.metadata()?.ino());
+
+        let prev_buffer_id = workspace.current_buffer.as_ref().unwrap().id()?;
+
+        let buffer = Buffer::new();
+        let buffer_id = workspace.add_buffer(buffer);
+        monitor.init_buffer(workspace.current_buffer.as_mut().unwrap())?;
+
+        workspace.select_buffer(prev_buffer_id);
+
+        Ok(WorkspaceModeData {
+            path: workspace.path.clone(),
+            selected_index: 0,
+            opened_dir_inos,
+            buffer_id: buffer_id,
+            prev_buffer_id,
+            highlight_ranges: Vec::new(),
+            current_render_index: 0,
+            max_index: 0,
+            selected_path: workspace.path.clone(),
+        })
+    }
+
+    fn update_max_index(&mut self) {
+        self.max_index = self.current_render_index - 1;
+    }
+
+    pub(super) fn render_workspace_tree(
+        &mut self,
+        workspace: &mut crate::workspace::Workspace,
+        monitor: &mut crate::view::monitor::Monitor,
+    ) -> Result<()> {
+        if !workspace.select_buffer(self.buffer_id) {
+            bail!("Not Workspace Buffer!");
+        }
+
+        self.current_render_index = 0;
+
+        if let Some(ref mut buffer) = workspace.current_buffer {
+            buffer.delete_range(Range::new(
+                Position { line: 0, offset: 0 },
+                Position {
+                    line: buffer.line_count(),
+                    offset: usize::MAX,
+                },
+            ));
+            buffer.cursor.move_to(Position { line: 0, offset: 0 });
+            self.highlight_ranges.resize(0, Default::default());
+        }
+
+        let mut depth = 0;
+        let root = self.path.clone();
+        self.render_dir(workspace, &root, &mut depth);
+
+        if let Some(ref mut buffer) = workspace.current_buffer {
+            buffer.cursor.move_to(Position {
+                line: self.selected_index,
+                offset: 0,
+            });
+            monitor.scroll_to_cursor(buffer)?;
+        }
+
+        let mut presenter = monitor.build_presenter()?;
+
+        let buffer = workspace.current_buffer.as_ref().unwrap();
+        let buffer_data = buffer.data();
+        presenter.print_buffer(
+            buffer,
+            &buffer_data,
+            &workspace.syntax_set,
+            Some(&self.highlight_ranges),
+            None,
+        )?;
+
+        let mode_name_data = StatusLineData {
+            content: " WORKSPACE ".to_string(),
+            color: Colors::Inverted,
+            style: CharStyle::Bold,
+        };
+        let workspace_path_data = StatusLineData {
+            content: format!(" {}", self.path.display()),
+            color: Colors::Focused,
+            style: CharStyle::Bold,
+        };
+        presenter.print_status_line(&[mode_name_data, workspace_path_data])?;
+        presenter.present()?;
+
+        monitor.terminal.set_cursor(None)?;
+        monitor.terminal.present()?;
+
+        self.update_max_index();
+        Ok(())
+    }
+
+    fn entry_sort(a: &DirEntry, b: &DirEntry) -> std::cmp::Ordering {
+        if a.file_type().is_dir() && b.file_type().is_dir() {
+            return a.file_name().cmp(b.file_name());
+        }
+
+        if a.file_type().is_dir() {
+            return std::cmp::Ordering::Less;
+        } else if b.file_type().is_dir() {
+            return std::cmp::Ordering::Greater;
+        }
+
+        a.file_name().cmp(b.file_name())
+    }
+
+    // 需要当前buffer为workspace buffer才能调用该方法
+    fn render_dir(&mut self, workspace: &mut Workspace, root_path: &PathBuf, depth: &mut usize) {
+        let walkdir = WalkDir::new(root_path)
+            .max_depth(1)
+            .sort_by(Self::entry_sort);
+
+        let mut iter = walkdir.into_iter();
+
+        if let Some(entry) = iter.next() {
+            if let Ok(entry) = entry {
+                let target_modified = workspace
+                    .get_buffer_with_ino(entry.ino())
+                    .map(|x| x.modified());
+
+                let buffer = workspace.current_buffer.as_mut().unwrap();
+                let ino = entry.ino();
+                buffer.cursor.move_down();
+                self.print_entry(
+                    buffer,
+                    entry,
+                    *depth,
+                    self.opened_dir_inos.contains(&ino),
+                    target_modified,
+                );
+                *depth += 1;
+                if !self.opened_dir_inos.contains(&ino) {
+                    return;
+                }
+            }
+        }
+
+        for entry in iter {
+            if let Ok(entry) = entry {
+                self.render_entry(workspace, entry, depth);
+            }
+        }
+    }
+
+    fn render_entry(&mut self, workspace: &mut Workspace, entry: DirEntry, depth: &mut usize) {
+        let target_modified = workspace
+            .get_buffer_with_ino(entry.ino())
+            .map(|x| x.modified());
+        let buffer = workspace.current_buffer.as_mut().unwrap();
+        if entry.file_type().is_dir() {
+            if self.opened_dir_inos.contains(&entry.ino()) {
+                self.render_dir(workspace, &entry.path().to_path_buf(), depth);
+                *depth -= 1;
+            } else {
+                self.print_entry(buffer, entry, *depth, false, target_modified);
+            }
+        } else {
+            self.print_entry(buffer, entry, *depth, false, target_modified);
+        }
+    }
+
+    fn print_entry(
+        &mut self,
+        buffer: &mut Buffer,
+        entry: DirEntry,
+        depth: usize,
+        is_open: bool,
+        target_buffer_modified: Option<bool>,
+    ) {
+        let prefix = " ".repeat(depth)
+            + if entry.file_type().is_dir() {
+                if is_open {
+                    "- "
+                } else {
+                    "+ "
+                }
+            } else {
+                "| "
+            };
+
+        buffer.insert(&prefix);
+        buffer.cursor.move_to(Position {
+            line: buffer.cursor.line,
+            offset: buffer.cursor.offset + prefix.graphemes(true).count(),
+        });
+
+        let start = buffer.cursor.position;
+        let file_name = entry.file_name().to_str().unwrap_or_default();
+
+        buffer.insert(file_name);
+        buffer.cursor.move_to(Position {
+            line: buffer.cursor.line,
+            offset: buffer.cursor.offset + file_name.graphemes(true).count(),
+        });
+        let end = buffer.cursor.position;
+
+        buffer.insert("\n");
+        buffer.cursor.move_down();
+
+        if self.selected_index == self.current_render_index {
+            self.highlight_ranges.push((
+                Range::new(start, end),
+                CharStyle::Bold,
+                Colors::CustomForeground(Color::Cyan),
+            ));
+
+            self.selected_path = entry.into_path();
+        } else if let Some(modified) = target_buffer_modified {
+            if modified {
+                self.highlight_ranges.push((
+                    Range::new(start, end),
+                    CharStyle::Bold,
+                    Colors::CustomForeground(Color::Yellow),
+                ));
+            } else {
+                self.highlight_ranges.push((
+                    Range::new(start, end),
+                    CharStyle::Bold,
+                    Colors::CustomForeground(Color::Green),
+                ));
+            }
+        }
+
+        self.current_render_index += 1;
+    }
+
+    /// 打开当前选择的节点,若返回true则表示打开的是文件而非dir,需要回退normal模式
+    pub fn open(&mut self, workspace: &mut Workspace, monitor: &mut Monitor) -> Result<bool> {
+        if self.selected_path.is_dir() {
+            let ino = self.selected_path.metadata()?.ino();
+            if self.opened_dir_inos.contains(&ino) {
+                self.opened_dir_inos.remove(&ino);
+            } else {
+                self.opened_dir_inos.insert(ino);
+            }
+
+            Ok(false)
+        } else {
+            let buffer = Buffer::from_file(&self.selected_path)?;
+            let id = workspace.add_buffer(buffer);
+            workspace.select_buffer(id);
+            monitor.init_buffer(workspace.current_buffer.as_mut().unwrap())?;
+            self.prev_buffer_id = id;
+            Ok(true)
+        }
+    }
+
+    pub fn move_down(&mut self) {
+        if self.selected_index == self.max_index {
+            return;
+        }
+        self.selected_index += 1;
+    }
+
+    pub fn move_up(&mut self) {
+        if self.selected_index == 0 {
+            return;
+        }
+        self.selected_index -= 1;
+    }
+}
+
+pub struct WorkspaceRender;
+
+impl ModeRenderer for WorkspaceRender {
+    fn render(
+        workspace: &mut crate::workspace::Workspace,
+        monitor: &mut crate::view::monitor::Monitor,
+        mode: &mut super::ModeData,
+    ) -> super::Result<()> {
+        if let ModeData::Workspace(mode_data) = mode {
+            return mode_data.render_workspace_tree(workspace, monitor);
+        } else {
+            bail!("Workspace mode cannot receive data other than WorkspaceModeData")
+        }
+    }
+}

+ 8 - 1
src/modules/input/default.yaml

@@ -6,6 +6,7 @@ normal:
   ctrl-c: app::exit
   ctrl-c: app::exit
   i: app::to_insert_mode
   i: app::to_insert_mode
   backspace: cursor::move_left
   backspace: cursor::move_left
+  w: app::to_workspace_mode
 insert:
 insert:
   escape: app::to_normal_mode
   escape: app::to_normal_mode
   left: cursor::move_left
   left: cursor::move_left
@@ -22,4 +23,10 @@ insert:
   backspace: insert::backspace
   backspace: insert::backspace
   tab: buffer::insert_tab
   tab: buffer::insert_tab
   _: 
   _: 
-    - buffer::insert_char
+    - buffer::insert_char
+workspace:
+  up: workspace::move_up
+  down: workspace::move_down
+  enter: workspace::enter
+  escape: workspace::to_normal_mode
+  ctrl-c: app::exit

+ 1 - 1
src/util/range.rs

@@ -1,7 +1,7 @@
 use crate::util::position::Position;
 use crate::util::position::Position;
 
 
 /// Range: 左开右闭区间
 /// Range: 左开右闭区间
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Default)]
 pub struct Range {
 pub struct Range {
     start: Position,
     start: Position,
     end: Position,
     end: Position,

+ 2 - 1
src/view/presenter.rs

@@ -97,6 +97,7 @@ impl<'a> Presenter<'a> {
             };
             };
 
 
             let len = content.len();
             let len = content.len();
+            warn!("line {line}, offset {offset}, content {content}");
             self.print(&Position { line, offset }, data.style, data.color, content);
             self.print(&Position { line, offset }, data.style, data.color, content);
             offset += len;
             offset += len;
         }
         }
@@ -110,7 +111,7 @@ impl<'a> Presenter<'a> {
         buffer: &Buffer,
         buffer: &Buffer,
         buffer_data: &'a str,
         buffer_data: &'a str,
         syntax_set: &'a SyntaxSet,
         syntax_set: &'a SyntaxSet,
-        highlights: Option<&[Range]>,
+        highlights: Option<&'a [(Range, CharStyle, Colors)]>,
         lexeme_mapper: Option<&'a mut dyn LexemeMapper>,
         lexeme_mapper: Option<&'a mut dyn LexemeMapper>,
     ) -> Result<()> {
     ) -> Result<()> {
         let scroll_offset = self.view.get_scroll_controller(buffer).line_offset();
         let scroll_offset = self.view.get_scroll_controller(buffer).line_offset();

+ 22 - 8
src/view/render/render_buffer.rs

@@ -33,13 +33,13 @@ pub struct CachedCell {
 
 
 #[derive(Debug)]
 #[derive(Debug)]
 pub struct CachedRenderBuffer {
 pub struct CachedRenderBuffer {
-    pub cells: Vec<CachedCell>,
+    pub cells: Vec<Option<CachedCell>>,
 }
 }
 
 
 impl CachedRenderBuffer {
 impl CachedRenderBuffer {
     pub fn new(width: usize, height: usize) -> CachedRenderBuffer {
     pub fn new(width: usize, height: usize) -> CachedRenderBuffer {
         CachedRenderBuffer {
         CachedRenderBuffer {
-            cells: vec![CachedCell::default(); width * height],
+            cells: vec![None; width * height],
         }
         }
     }
     }
 
 
@@ -48,14 +48,28 @@ impl CachedRenderBuffer {
         if index < self.cells.len() {
         if index < self.cells.len() {
             let cache = &mut self.cells[index];
             let cache = &mut self.cells[index];
             let cell_content = String::from_iter(cell.content.chars());
             let cell_content = String::from_iter(cell.content.chars());
-            let equal = cache.colors == cell.colors
-                && cache.style == cell.style
-                && cache.content == cell_content;
+
+            let equal = if let Some(cache) = cache {
+                let equal = cache.colors == cell.colors
+                    && cache.style == cell.style
+                    && cache.content == cell_content;
+
+                equal
+            } else {
+                false
+            };
 
 
             if !equal {
             if !equal {
-                cache.colors = cell.colors;
-                cache.style = cell.style;
-                cache.content = cell_content;
+                let mut cache_cell = CachedCell::default();
+                let content_len = cell_content.len();
+                cache_cell.colors = cell.colors;
+                cache_cell.style = cell.style;
+                cache_cell.content = cell_content;
+                for i in (index + 1)..(index + content_len) {
+                    self.cells[i] = None
+                }
+
+                self.cells[index] = Some(cache_cell);
             }
             }
 
 
             return equal;
             return equal;

+ 13 - 9
src/view/render/renderer.rs

@@ -30,7 +30,7 @@ pub struct Renderer<'a, 'p> {
     render_buffer: &'a mut RenderBuffer<'p>,
     render_buffer: &'a mut RenderBuffer<'p>,
     terminal: &'a dyn Terminal,
     terminal: &'a dyn Terminal,
     theme: &'a Theme,
     theme: &'a Theme,
-    highlight_ranges: Option<&'a [Range]>,
+    highlight_ranges: Option<&'a [(Range, CharStyle, Colors)]>,
     scroll_offset: usize,
     scroll_offset: usize,
     line_number_iter: LineNumberStringIter,
     line_number_iter: LineNumberStringIter,
     content_start_of_line: usize,
     content_start_of_line: usize,
@@ -49,7 +49,7 @@ impl<'a, 'p> Renderer<'a, 'p> {
         render_buffer: &'a mut RenderBuffer<'p>,
         render_buffer: &'a mut RenderBuffer<'p>,
         terminal: &'a dyn Terminal,
         terminal: &'a dyn Terminal,
         perferences: &'a dyn Perferences,
         perferences: &'a dyn Perferences,
-        highlight_ranges: Option<&'a [Range]>,
+        highlight_ranges: Option<&'a [(Range, CharStyle, Colors)]>,
         cached_render_state: &'a Rc<RefCell<HashMap<usize, RenderState>>>,
         cached_render_state: &'a Rc<RefCell<HashMap<usize, RenderState>>>,
         theme: &'a Theme,
         theme: &'a Theme,
         syntax_set: &'a SyntaxSet,
         syntax_set: &'a SyntaxSet,
@@ -347,15 +347,19 @@ impl<'a, 'p> Renderer<'a, 'p> {
     fn current_char_style(&self, token_color: Color) -> (CharStyle, Colors) {
     fn current_char_style(&self, token_color: Color) -> (CharStyle, Colors) {
         let (style, colors) = match self.highlight_ranges {
         let (style, colors) = match self.highlight_ranges {
             Some(highlight_ranges) => {
             Some(highlight_ranges) => {
-                for range in highlight_ranges {
+                for (range, style, colors) in highlight_ranges {
                     if range.includes(&self.buffer_position) {
                     if range.includes(&self.buffer_position) {
-                        // We're inside of one of the highlighted areas.
-                        // Return early with highlight colors.
-                        if range.includes(&self.buffer.cursor) {
-                            return (CharStyle::Bold, Colors::SelectMode);
+                        // 修正背景色
+                        let fix_colors = if let Colors::CustomForeground(color) = colors {
+                            if self.on_cursor_line() {
+                                Colors::CustomFocusedForeground(*color)
+                            } else {
+                                *colors
+                            }
                         } else {
                         } else {
-                            return (CharStyle::Reverse, Colors::Default);
-                        }
+                            *colors
+                        };
+                        return (*style, fix_colors);
                     }
                     }
                 }
                 }
 
 

+ 46 - 21
src/workspace.rs

@@ -1,7 +1,9 @@
 use std::{
 use std::{
     cell::Ref,
     cell::Ref,
-    env, mem,
-    path::{self, Path, PathBuf},
+    collections::HashMap,
+    env,
+    os::unix::fs::MetadataExt,
+    path::{Path, PathBuf},
 };
 };
 
 
 use crate::{
 use crate::{
@@ -15,11 +17,12 @@ use crate::buffer::Buffer;
 
 
 pub struct Workspace {
 pub struct Workspace {
     pub path: PathBuf,
     pub path: PathBuf,
-    buffers: Vec<Buffer>,
+    buffers: HashMap<usize, Buffer>,
+    // ino -> id
+    buffers_ino_map: HashMap<u64, usize>,
     pub current_buffer: Option<Buffer>,
     pub current_buffer: Option<Buffer>,
     pub syntax_set: SyntaxSet,
     pub syntax_set: SyntaxSet,
     buffer_ida: usize,
     buffer_ida: usize,
-    current_buffer_index: Option<usize>,
 }
 }
 
 
 impl Workspace {
 impl Workspace {
@@ -96,27 +99,34 @@ impl Workspace {
 
 
         Ok(Workspace {
         Ok(Workspace {
             path: path.canonicalize()?,
             path: path.canonicalize()?,
-            buffers: vec![],
+            buffers: HashMap::new(),
+            buffers_ino_map: HashMap::new(),
             current_buffer: None,
             current_buffer: None,
             syntax_set,
             syntax_set,
             buffer_ida: 0,
             buffer_ida: 0,
-            current_buffer_index: None,
         })
         })
     }
     }
 
 
-    pub fn add_buffer(&mut self, mut buffer: Buffer) {
-        buffer.id = Some(self.alloc_buffer_id());
+    pub fn add_buffer(&mut self, mut buffer: Buffer) -> usize {
+        let id = self.alloc_buffer_id();
+        buffer.id = Some(id);
 
 
-        let target_index = self.current_buffer_index.map(|x| x + 1).unwrap_or(0);
+        if let Some(ref path) = buffer.path {
+            if let Ok(metadata) = path.metadata() {
+                self.buffers_ino_map.insert(metadata.ino(), id);
+            }
+        }
 
 
-        self.buffers.insert(target_index, buffer);
-        self.select_buffer(target_index);
+        self.buffers.insert(id, buffer);
+        self.select_buffer(id);
 
 
         if let Some(buffer) = self.current_buffer.as_ref() {
         if let Some(buffer) = self.current_buffer.as_ref() {
             if buffer.syntax_definition.is_none() {
             if buffer.syntax_definition.is_none() {
                 let _ = self.update_current_syntax();
                 let _ = self.update_current_syntax();
             }
             }
         }
         }
+
+        return id;
     }
     }
 
 
     fn alloc_buffer_id(&mut self) -> usize {
     fn alloc_buffer_id(&mut self) -> usize {
@@ -124,20 +134,35 @@ impl Workspace {
         self.buffer_ida
         self.buffer_ida
     }
     }
 
 
-    fn select_buffer(&mut self, index: usize) -> bool {
+    pub fn get_buffer(&self, id: usize) -> Option<&Buffer> {
+        if let Some(ref buffer) = self.current_buffer {
+            if buffer.id.unwrap() == id {
+                return Some(buffer);
+            }
+        }
+        return self.buffers.get(&id);
+    }
+
+    pub fn get_buffer_with_ino(&self, ino: u64) -> Option<&Buffer> {
+        if let Some(id) = self.buffers_ino_map.get(&ino) {
+            return self.get_buffer(*id);
+        }
+        None
+    }
+
+    pub fn select_buffer(&mut self, id: usize) -> bool {
         // 将当前buffer放回
         // 将当前buffer放回
-        if let Some(buffer) = self.current_buffer.as_mut() {
-            mem::swap(
-                buffer,
-                &mut self.buffers[self.current_buffer_index.unwrap()],
-            );
+        if let Some(buffer) = self.current_buffer.take() {
+            if buffer.id.unwrap() == id {
+                self.current_buffer = Some(buffer);
+                return true;
+            }
+            self.buffers.insert(buffer.id.unwrap(), buffer);
         }
         }
 
 
         // 选择新buffer
         // 选择新buffer
-        if let Some(buffer) = self.buffers.get_mut(index) {
-            self.current_buffer = Some(mem::take(buffer));
-            self.current_buffer_index.replace(index);
-
+        if let Some(buffer) = self.buffers.remove(&id) {
+            self.current_buffer = Some(buffer);
             return true;
             return true;
         }
         }