renderer.rs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. use std::borrow::Cow;
  2. use std::cell::RefCell;
  3. use std::collections::HashMap;
  4. use std::rc::Rc;
  5. use std::str::FromStr;
  6. use crate::modules::perferences::Perferences;
  7. use crate::plugin::system::PluginSystem;
  8. use crate::view::colors::to_rgb;
  9. use crate::{buffer::Buffer, util::line_iterator::LineIterator, view::terminal::Terminal};
  10. use crate::{errors::*, get_application};
  11. use crossterm::style::Color;
  12. use held_core::plugin::Plugin;
  13. use held_core::utils::position::Position;
  14. use held_core::utils::range::Range;
  15. use held_core::view::colors::Colors;
  16. use held_core::view::render::ContentRenderBuffer;
  17. use held_core::view::style::CharStyle;
  18. use syntect::highlighting::{HighlightIterator, Highlighter, Style, Theme};
  19. use syntect::parsing::{ScopeStack, SyntaxSet};
  20. use unicode_segmentation::UnicodeSegmentation;
  21. use super::line_number_string_iter::LineNumberStringIter;
  22. use super::render_buffer::Cell;
  23. use super::render_state::RenderState;
  24. use super::{lexeme_mapper::LexemeMapper, render_buffer::RenderBuffer};
  25. const RENDER_CACHE_FREQUENCY: usize = 100;
  26. pub struct Renderer<'a, 'p> {
  27. buffer: &'a Buffer,
  28. render_buffer: &'a mut RenderBuffer<'p>,
  29. terminal: &'a dyn Terminal,
  30. theme: &'a Theme,
  31. highlight_ranges: Option<&'a [(Range, CharStyle, Colors)]>,
  32. scroll_offset: usize,
  33. line_number_iter: LineNumberStringIter,
  34. content_start_of_line: usize,
  35. cached_render_state: &'a Rc<RefCell<HashMap<usize, RenderState>>>,
  36. syntax_set: &'a SyntaxSet,
  37. screen_position: Position,
  38. buffer_position: Position,
  39. cursor_position: Option<Position>,
  40. current_style: Style,
  41. perferences: &'a dyn Perferences,
  42. plugin_system: &'a mut PluginSystem,
  43. }
  44. impl<'a, 'p> Renderer<'a, 'p> {
  45. pub fn new(
  46. buffer: &'a Buffer,
  47. render_buffer: &'a mut RenderBuffer<'p>,
  48. terminal: &'a dyn Terminal,
  49. perferences: &'a dyn Perferences,
  50. highlight_ranges: Option<&'a [(Range, CharStyle, Colors)]>,
  51. cached_render_state: &'a Rc<RefCell<HashMap<usize, RenderState>>>,
  52. theme: &'a Theme,
  53. syntax_set: &'a SyntaxSet,
  54. scroll_offset: usize,
  55. plugin_system: &'a mut PluginSystem,
  56. ) -> Renderer<'a, 'p> {
  57. let line_number_iter = LineNumberStringIter::new(buffer, scroll_offset);
  58. let content_start_of_line = line_number_iter.width() + 1;
  59. Self {
  60. buffer,
  61. render_buffer,
  62. terminal,
  63. theme,
  64. scroll_offset,
  65. syntax_set,
  66. cached_render_state,
  67. screen_position: Position::default(),
  68. buffer_position: Position::default(),
  69. cursor_position: None,
  70. current_style: Style::default(),
  71. perferences,
  72. highlight_ranges,
  73. line_number_iter,
  74. content_start_of_line,
  75. plugin_system,
  76. }
  77. }
  78. pub fn render(
  79. &mut self,
  80. lines: LineIterator<'a>,
  81. mut lexeme_mapper: Option<&mut dyn LexemeMapper>,
  82. ) -> Result<Option<Position>> {
  83. self.terminal.set_cursor(None)?;
  84. self.render_line_number();
  85. let highlighter = Highlighter::new(&self.theme);
  86. let syntax_definition = self
  87. .buffer
  88. .syntax_definition
  89. .as_ref()
  90. .ok_or("Buffer has no syntax definition")?;
  91. let focused_style = Renderer::mapper_keyword_style(&highlighter);
  92. let blurred_style = Renderer::mapper_comment_style(&highlighter);
  93. let (cached_line_num, mut state) = self
  94. .current_cached_render_state()
  95. .unwrap_or((0, RenderState::new(&highlighter, syntax_definition)));
  96. for (line_num, line_data) in lines {
  97. if line_num >= cached_line_num {
  98. if line_num % RENDER_CACHE_FREQUENCY == 0 {
  99. self.cached_render_state
  100. .borrow_mut()
  101. .insert(line_num, state.clone());
  102. }
  103. if self.before_visible() {
  104. self.try_to_advance_to_next_line(&line_data);
  105. continue;
  106. }
  107. if self.after_visible() {
  108. break;
  109. }
  110. let events = state
  111. .parse
  112. .parse_line(&line_data, self.syntax_set)
  113. .chain_err(|| "Failed to parse buffer")?;
  114. let styled_lexemes =
  115. HighlightIterator::new(&mut state.highlight, &events, &line_data, &highlighter);
  116. for (style, lexeme) in styled_lexemes {
  117. if let Some(ref mut mapper) = lexeme_mapper {
  118. let mapped_lexemes = mapper.map(lexeme, self.buffer_position);
  119. for mapped_lexeme in mapped_lexemes {
  120. match mapped_lexeme {
  121. super::lexeme_mapper::MappedLexeme::Focused(val) => {
  122. self.current_style = focused_style;
  123. self.render_lexeme(val.to_string());
  124. }
  125. super::lexeme_mapper::MappedLexeme::Blurred(val) => {
  126. self.current_style = blurred_style;
  127. self.render_lexeme(val.to_string());
  128. }
  129. }
  130. }
  131. } else {
  132. self.current_style = style;
  133. self.render_lexeme(lexeme);
  134. }
  135. }
  136. }
  137. self.try_to_advance_to_next_line(&line_data);
  138. }
  139. self.render_plugins()?;
  140. Ok(self.cursor_position)
  141. }
  142. fn mapper_keyword_style(highlighter: &Highlighter) -> Style {
  143. highlighter.style_for_stack(
  144. ScopeStack::from_str("keyword")
  145. .unwrap_or_default()
  146. .as_slice(),
  147. )
  148. }
  149. fn render_plugins(&mut self) -> Result<()> {
  150. let plugin_buffers = self.plugin_system.on_render_content();
  151. for plugin_buffer in plugin_buffers {
  152. self.render_plugin(plugin_buffer)?;
  153. }
  154. Ok(())
  155. }
  156. fn render_plugin(&mut self, buffer: ContentRenderBuffer) -> Result<()> {
  157. let mut line = 0;
  158. let mut offset = 0;
  159. let init_pos = buffer.rectangle.position;
  160. warn!("plugin cells {:?}", buffer.cells);
  161. for cell in buffer.cells {
  162. if let Some(cell) = cell {
  163. self.render_cell(
  164. Position {
  165. line: init_pos.line + line,
  166. offset: init_pos.offset + offset,
  167. },
  168. cell.style,
  169. cell.colors,
  170. cell.content.to_string(),
  171. );
  172. }
  173. offset += 1;
  174. if offset == buffer.rectangle.width {
  175. offset = 0;
  176. line += 1;
  177. }
  178. }
  179. Ok(())
  180. }
  181. fn mapper_comment_style(highlighter: &Highlighter) -> Style {
  182. highlighter.style_for_stack(
  183. ScopeStack::from_str("keyword")
  184. .unwrap_or_default()
  185. .as_slice(),
  186. )
  187. }
  188. fn current_cached_render_state(&self) -> Option<(usize, RenderState)> {
  189. self.cached_render_state
  190. .borrow()
  191. .iter()
  192. .filter(|(k, _)| **k < self.scroll_offset)
  193. .max_by(|a, b| a.0.cmp(b.0))
  194. .map(|x| (*x.0, x.1.clone()))
  195. }
  196. fn after_visible(&self) -> bool {
  197. self.screen_position.line >= (self.terminal.height().unwrap() - 1)
  198. }
  199. fn before_visible(&self) -> bool {
  200. self.buffer_position.line < self.scroll_offset
  201. }
  202. fn inside_visible(&self) -> bool {
  203. !self.before_visible() && !self.after_visible()
  204. }
  205. fn set_cursor(&mut self) {
  206. if self.inside_visible() && *self.buffer.cursor == self.buffer_position {
  207. self.cursor_position = Some(self.screen_position);
  208. get_application().state_data.cursor_state.screen_position = self.screen_position;
  209. }
  210. }
  211. fn on_cursor_line(&self) -> bool {
  212. self.buffer.cursor.line == self.buffer_position.line
  213. }
  214. fn try_to_advance_to_next_line(&mut self, line: &str) {
  215. if line.chars().last().map(|x| x == '\n').unwrap_or(false) {
  216. self.advance_to_next_line();
  217. }
  218. }
  219. fn advance_to_next_line(&mut self) {
  220. if self.inside_visible() {
  221. self.set_cursor();
  222. self.render_rest_of_line();
  223. self.screen_position.line += 1;
  224. }
  225. self.buffer_position.line += 1;
  226. self.buffer_position.offset = 0;
  227. self.render_line_number();
  228. }
  229. fn render_rest_of_line(&mut self) {
  230. let on_cursor_line = self.on_cursor_line();
  231. for offset in self.screen_position.offset..self.terminal.width().unwrap() {
  232. let colors = if on_cursor_line {
  233. Colors::Focused
  234. } else {
  235. Colors::Default
  236. };
  237. self.render_cell(
  238. Position {
  239. line: self.screen_position.line,
  240. offset,
  241. },
  242. CharStyle::Default,
  243. colors,
  244. " ",
  245. );
  246. }
  247. }
  248. fn render_line_number(&mut self) {
  249. if !self.inside_visible() {
  250. return;
  251. }
  252. let line_number = self.line_number_iter.next().unwrap();
  253. let is_on_cursor_line = self.on_cursor_line();
  254. let style = if is_on_cursor_line {
  255. CharStyle::Bold
  256. } else {
  257. CharStyle::Default
  258. };
  259. // 渲染行号
  260. self.render_cell(
  261. Position {
  262. line: self.screen_position.line,
  263. offset: 0,
  264. },
  265. style,
  266. Colors::Focused,
  267. line_number,
  268. );
  269. // 行号后的gap
  270. let gap_color = if is_on_cursor_line {
  271. Colors::Focused
  272. } else {
  273. Colors::Default
  274. };
  275. self.render_cell(
  276. Position {
  277. line: self.screen_position.line,
  278. offset: self.line_number_iter.width(),
  279. },
  280. style,
  281. gap_color,
  282. " ",
  283. );
  284. self.screen_position.offset = self.line_number_iter.width() + 1;
  285. }
  286. fn render_lexeme<T: Into<Cow<'a, str>>>(&mut self, lexeme: T) {
  287. for character in lexeme.into().graphemes(true) {
  288. if character == "\n" {
  289. continue;
  290. }
  291. self.set_cursor();
  292. let token_color = to_rgb(self.current_style.foreground);
  293. let (style, color) = self.current_char_style(token_color);
  294. if self.perferences.line_wrapping()
  295. && self.screen_position.offset == self.terminal.width().unwrap() - 1
  296. {
  297. self.render_cell(self.screen_position, style, color, character.to_string());
  298. self.buffer_position.offset += 1;
  299. // 屏幕上换行但是渲染原来的line
  300. let prefix_len = self.content_start_of_line;
  301. let prefix = " ".repeat(prefix_len);
  302. self.screen_position.offset = 0;
  303. self.screen_position.line += 1;
  304. self.render_cell(
  305. Position {
  306. line: self.screen_position.line,
  307. offset: self.screen_position.offset,
  308. },
  309. style,
  310. Colors::Default,
  311. prefix,
  312. );
  313. self.screen_position.offset += prefix_len;
  314. } else if character == "\t" {
  315. let tab_len = self.perferences.tab_width();
  316. let width = tab_len - (self.screen_position.offset + 1) % tab_len;
  317. let tab_str = " ".repeat(width);
  318. self.render_lexeme(tab_str);
  319. } else {
  320. self.render_cell(self.screen_position, style, color, character.to_string());
  321. self.screen_position.offset += 1;
  322. self.buffer_position.offset += 1;
  323. }
  324. // 退出循环前更新
  325. self.set_cursor();
  326. }
  327. }
  328. fn render_cell<C: Into<Cow<'p, str>>>(
  329. &mut self,
  330. position: Position,
  331. style: CharStyle,
  332. colors: Colors,
  333. content: C,
  334. ) {
  335. self.render_buffer.set_cell(
  336. position,
  337. Cell {
  338. content: content.into(),
  339. colors,
  340. style,
  341. },
  342. );
  343. }
  344. fn current_char_style(&self, token_color: Color) -> (CharStyle, Colors) {
  345. let (style, colors) = match self.highlight_ranges {
  346. Some(highlight_ranges) => {
  347. for (range, style, colors) in highlight_ranges {
  348. if range.includes(&self.buffer_position) {
  349. // 修正背景色
  350. let fix_colors = if let Colors::CustomForeground(color) = colors {
  351. if self.on_cursor_line() {
  352. Colors::CustomFocusedForeground(*color)
  353. } else {
  354. *colors
  355. }
  356. } else {
  357. *colors
  358. };
  359. return (*style, fix_colors);
  360. }
  361. }
  362. // We aren't inside one of the highlighted areas.
  363. // Fall back to other styling considerations.
  364. if self.on_cursor_line() {
  365. (
  366. CharStyle::Default,
  367. Colors::CustomFocusedForeground(token_color),
  368. )
  369. } else {
  370. (CharStyle::Default, Colors::CustomForeground(token_color))
  371. }
  372. }
  373. None => {
  374. if self.on_cursor_line() {
  375. (
  376. CharStyle::Default,
  377. Colors::CustomFocusedForeground(token_color),
  378. )
  379. } else {
  380. (CharStyle::Default, Colors::CustomForeground(token_color))
  381. }
  382. }
  383. };
  384. (style, colors)
  385. }
  386. }
  387. #[cfg(test)]
  388. mod tests {
  389. use std::{
  390. cell::RefCell,
  391. collections::HashMap,
  392. io::{BufReader, Cursor},
  393. path::Path,
  394. rc::Rc,
  395. };
  396. use syntect::{highlighting::ThemeSet, parsing::SyntaxSet};
  397. use crate::{
  398. buffer::Buffer,
  399. modules::perferences::DummyPerferences,
  400. util::line_iterator::LineIterator,
  401. view::{
  402. colors::map::ColorMap,
  403. render::render_buffer::{CachedRenderBuffer, RenderBuffer},
  404. terminal::{cross_terminal::CrossTerminal, Terminal},
  405. },
  406. };
  407. use super::Renderer;
  408. #[test]
  409. fn test_display() {
  410. let terminal = CrossTerminal::new().unwrap();
  411. let mut buffer = Buffer::from_file(Path::new("src/main.rs")).unwrap();
  412. let mut render_buffer = RenderBuffer::new(
  413. terminal.width().unwrap(),
  414. terminal.height().unwrap(),
  415. Rc::new(RefCell::new(CachedRenderBuffer::new(
  416. terminal.width().unwrap(),
  417. terminal.height().unwrap(),
  418. ))),
  419. );
  420. let perferences = DummyPerferences;
  421. let cached_render_state = Rc::new(RefCell::new(HashMap::new()));
  422. let mut reader = BufReader::new(Cursor::new(include_str!(
  423. "../../themes/solarized_dark.tmTheme"
  424. )));
  425. let theme = ThemeSet::load_from_reader(&mut reader).unwrap();
  426. let syntax_set = SyntaxSet::load_defaults_newlines();
  427. let definition = buffer
  428. .file_extension()
  429. .and_then(|ex| syntax_set.find_syntax_by_extension(&ex))
  430. .or_else(|| Some(syntax_set.find_syntax_plain_text()))
  431. .cloned();
  432. buffer.syntax_definition = definition;
  433. let binding = buffer.data();
  434. {
  435. let mut renderer = Renderer::new(
  436. &buffer,
  437. &mut render_buffer,
  438. &terminal,
  439. &perferences,
  440. None,
  441. &cached_render_state,
  442. &theme,
  443. &syntax_set,
  444. 0,
  445. todo!(),
  446. );
  447. renderer.render(LineIterator::new(&binding), None).unwrap();
  448. }
  449. for (position, cell) in render_buffer.iter() {
  450. terminal
  451. .print(
  452. &position,
  453. cell.style,
  454. theme.map_colors(cell.colors),
  455. &cell.content,
  456. )
  457. .unwrap();
  458. }
  459. terminal.present().unwrap();
  460. }
  461. }