Merge branch 'master' into HEAD

macos-click-through
AnhQuan Nguyen 5 years ago
commit 37f55f4962

@ -114,6 +114,20 @@ pub enum WindowAnchor {
SouthEast,
}
#[derive(Debug)]
pub enum EditorMode {
// The set of modes reported will change in new versions of Nvim, for
// instance more sub-modes and temporary states might be represented as
// separate modes. (however we can safely do this as these are the main modes)
// for instance if we are in Terminal mode and even though status-line shows Terminal,
// we still get one of these as the _editor_ mode
Normal,
Insert,
Visual,
CmdLine,
Unknown(String),
}
#[derive(Debug)]
pub enum RedrawEvent {
SetTitle {
@ -126,6 +140,7 @@ pub enum RedrawEvent {
gui_option: GuiOption,
},
ModeChange {
mode: EditorMode,
mode_index: u64,
},
MouseOn,
@ -373,9 +388,17 @@ fn parse_option_set(option_set_arguments: Vec<Value>) -> Result<RedrawEvent> {
}
fn parse_mode_change(mode_change_arguments: Vec<Value>) -> Result<RedrawEvent> {
let [_mode, mode_index] = extract_values(mode_change_arguments, [Value::Nil, Value::Nil])?;
let [mode, mode_index] = extract_values(mode_change_arguments, [Value::Nil, Value::Nil])?;
let mode_name = parse_string(mode)?;
Ok(RedrawEvent::ModeChange {
mode: match mode_name.as_str() {
"normal" => EditorMode::Normal,
"insert" => EditorMode::Insert,
"visual" => EditorMode::Visual,
"cmdline_normal" => EditorMode::CmdLine,
_ => EditorMode::Unknown(mode_name),
},
mode_index: parse_u64(mode_index)?,
})
}

@ -43,7 +43,6 @@ pub struct Cursor {
pub blinkoff: Option<u64>,
pub style: Option<Arc<Style>>,
pub enabled: bool,
pub mode_list: Vec<CursorMode>,
}
impl Cursor {
@ -57,7 +56,6 @@ impl Cursor {
blinkon: None,
blinkoff: None,
enabled: true,
mode_list: Vec::new(),
}
}
@ -85,28 +83,27 @@ impl Cursor {
}
}
pub fn change_mode(&mut self, mode_index: u64, styles: &HashMap<u64, Arc<Style>>) {
if let Some(CursorMode {
pub fn change_mode(&mut self, cursor_mode: &CursorMode, styles: &HashMap<u64, Arc<Style>>) {
let CursorMode {
shape,
style_id,
cell_percentage,
blinkwait,
blinkon,
blinkoff,
}) = self.mode_list.get(mode_index as usize)
{
if let Some(shape) = shape {
self.shape = shape.clone();
}
} = cursor_mode;
if let Some(style_id) = style_id {
self.style = styles.get(style_id).cloned();
}
if let Some(shape) = shape {
self.shape = shape.clone();
}
self.cell_percentage = *cell_percentage;
self.blinkwait = *blinkwait;
self.blinkon = *blinkon;
self.blinkoff = *blinkoff;
if let Some(style_id) = style_id {
self.style = styles.get(style_id).cloned();
}
self.cell_percentage = *cell_percentage;
self.blinkwait = *blinkwait;
self.blinkon = *blinkon;
self.blinkoff = *blinkoff;
}
}

@ -10,7 +10,7 @@ use parking_lot::Mutex;
use skulpin::skia_safe::colors;
use unicode_segmentation::UnicodeSegmentation;
use crate::bridge::{GridLineCell, GuiOption, RedrawEvent};
use crate::bridge::{EditorMode, GridLineCell, GuiOption, RedrawEvent};
use crate::redraw_scheduler::REDRAW_SCHEDULER;
use crate::window::window_geometry_or_default;
pub use cursor::{Cursor, CursorMode, CursorShape};
@ -39,6 +39,8 @@ pub struct Editor {
pub default_style: Arc<Style>,
pub defined_styles: HashMap<u64, Arc<Style>>,
pub previous_style: Option<Arc<Style>>,
pub mode_list: Vec<CursorMode>,
pub current_mode: EditorMode,
}
impl Editor {
@ -57,6 +59,8 @@ impl Editor {
))),
defined_styles: HashMap::new(),
previous_style: None,
mode_list: Vec::new(),
current_mode: EditorMode::Unknown(String::from("")),
};
editor.grid.clear();
@ -66,10 +70,13 @@ impl Editor {
pub fn handle_redraw_event(&mut self, event: RedrawEvent) {
match event {
RedrawEvent::SetTitle { title } => self.title = title,
RedrawEvent::ModeInfoSet { cursor_modes } => self.cursor.mode_list = cursor_modes,
RedrawEvent::ModeInfoSet { cursor_modes } => self.mode_list = cursor_modes,
RedrawEvent::OptionSet { gui_option } => self.set_option(gui_option),
RedrawEvent::ModeChange { mode_index } => {
self.cursor.change_mode(mode_index, &self.defined_styles)
RedrawEvent::ModeChange { mode, mode_index } => {
if let Some(cursor_mode) = self.mode_list.get(mode_index as usize) {
self.cursor.change_mode(cursor_mode, &self.defined_styles);
self.current_mode = mode
}
}
RedrawEvent::MouseOn => {
self.mouse_enabled = true;
@ -194,15 +201,15 @@ impl Editor {
}
add_command(&mut draw_commands, command);
}
let should_clear = self.grid.should_clear;
let should_clear = self.grid.should_clear;
let draw_commands = draw_commands
.into_iter()
.filter(|command| {
let (x, y) = command.grid_position;
let min = (x as i64 - 1).max(0) as u64;
let max = (x + command.cell_width + 1).min(self.grid.width);
for char_index in min..max {
if self.grid.is_dirty_cell(char_index, y) {
return true;
@ -227,6 +234,7 @@ impl Editor {
};
let mut text = cell.text;
if let Some(times) = cell.repeat {
text = text.repeat(times as usize);
}
@ -247,6 +255,7 @@ impl Editor {
}
*column_pos += text.graphemes(true).count() as u64;
}
self.previous_style = style;
}

@ -48,6 +48,7 @@ impl RedrawScheduler {
pub fn schedule(&self, new_scheduled: Instant) {
trace!("Redraw scheduled for {:?}", new_scheduled);
let mut scheduled_frame = self.scheduled_frame.lock().unwrap();
if let Some(previous_scheduled) = *scheduled_frame {
if new_scheduled < previous_scheduled {
*scheduled_frame = Some(new_scheduled);
@ -60,18 +61,21 @@ impl RedrawScheduler {
pub fn queue_next_frame(&self) {
trace!("Next frame queued");
let buffer_frames = SETTINGS.get::<RedrawSettings>().extra_buffer_frames;
self.frames_queued
.store(buffer_frames as u16, Ordering::Relaxed);
}
pub fn should_draw(&self) -> bool {
let frames_queued = self.frames_queued.load(Ordering::Relaxed);
if frames_queued > 0 {
self.frames_queued
.store(frames_queued - 1, Ordering::Relaxed);
true
} else {
let mut next_scheduled_frame = self.scheduled_frame.lock().unwrap();
if let Some(scheduled_frame) = *next_scheduled_frame {
if scheduled_frame < Instant::now() {
*next_scheduled_frame = None;

@ -134,12 +134,14 @@ impl CursorVfx for PointHighlight {
if self.t == 1.0 {
return;
}
let mut paint = Paint::new(skulpin::skia_safe::colors::WHITE, None);
paint.set_blend_mode(BlendMode::SrcOver);
let base_color: Color = cursor.background(&colors).to_color();
let alpha = ease(ease_in_quad, settings.vfx_opacity, 0.0, self.t) as u8;
let color = Color::from_argb(alpha, base_color.r(), base_color.g(), base_color.b());
paint.set_color(color);
let size = 3.0 * font_size.1;

@ -9,6 +9,7 @@ use crate::redraw_scheduler::REDRAW_SCHEDULER;
use crate::renderer::CachingShaper;
use crate::settings::*;
use crate::bridge::EditorMode;
use animation_utils::*;
use blink::*;
@ -23,6 +24,7 @@ const STANDARD_CORNERS: &[(f32, f32); 4] = &[(-0.5, -0.5), (0.5, -0.5), (0.5, 0.
pub struct CursorSettings {
antialiasing: bool,
animation_length: f32,
animate_in_insert_mode: bool,
trail_size: f32,
vfx_mode: cursor_vfx::VfxMode,
vfx_opacity: f32,
@ -37,6 +39,7 @@ pub fn initialize_settings() {
SETTINGS.set(&CursorSettings {
antialiasing: true,
animation_length: 0.13,
animate_in_insert_mode: true,
trail_size: 0.7,
vfx_mode: cursor_vfx::VfxMode::Disabled,
vfx_opacity: 200.0,
@ -48,6 +51,10 @@ pub fn initialize_settings() {
});
register_nvim_setting!("cursor_antialiasing", CursorSettings::antialiasing);
register_nvim_setting!(
"cursor_animate_in_insert_mode",
CursorSettings::animate_in_insert_mode
);
register_nvim_setting!("cursor_animation_length", CursorSettings::animation_length);
register_nvim_setting!("cursor_trail_size", CursorSettings::trail_size);
register_nvim_setting!("cursor_vfx_mode", CursorSettings::vfx_mode);
@ -102,20 +109,9 @@ impl Corner {
font_dimensions: Point,
destination: Point,
dt: f32,
immediate_movement: bool,
) -> bool {
// Update destination if needed
let mut immediate_movement = false;
if destination != self.previous_destination {
let travel_distance = destination - self.previous_destination;
let chars_travel_x = travel_distance.x / font_dimensions.x;
if travel_distance.y == 0.0 && (chars_travel_x - 1.0).abs() < 0.1 {
// We're moving one character to the right. Make movement immediate to avoid lag
// while typing
immediate_movement = true;
}
self.t = 0.0;
self.start_position = self.current_position;
self.previous_destination = destination;
@ -162,7 +158,12 @@ impl Corner {
// We are at destination, move t out of 0-1 range to stop the animation
self.t = 2.0;
} else {
let corner_dt = dt * lerp(1.0, 1.0 - settings.trail_size, -direction_alignment);
let corner_dt = dt
* lerp(
1.0,
(1.0 - settings.trail_size).max(0.0).min(1.0),
-direction_alignment,
);
self.t = (self.t + corner_dt / settings.animation_length).min(1.0)
}
@ -211,6 +212,7 @@ impl CursorRenderer {
.enumerate()
.map(|(i, corner)| {
let (x, y) = STANDARD_CORNERS[i];
Corner {
relative_position: match cursor_shape {
CursorShape::Block => (x, y).into(),
@ -257,8 +259,10 @@ impl CursorRenderer {
let editor = EDITOR.lock();
let (_, grid_y) = cursor.position;
let (_, previous_y) = self.previous_position;
if grid_y == editor.grid.height - 1 && previous_y != grid_y {
self.command_line_delay += 1;
if self.command_line_delay < COMMAND_LINE_DELAY_FRAMES {
self.previous_position
} else {
@ -272,7 +276,7 @@ impl CursorRenderer {
};
let (grid_x, grid_y) = self.previous_position;
let (character, font_dimensions): (String, Point) = {
let (character, font_dimensions, in_insert_mode): (String, Point, bool) = {
let editor = EDITOR.lock();
let character = match editor.grid.get_cell(grid_x, grid_y) {
Some(Some((character, _))) => character.clone(),
@ -288,7 +292,13 @@ impl CursorRenderer {
(true, CursorShape::Block) => font_width * 2.0,
_ => font_width,
};
(character, (font_width, font_height).into())
let in_insert_mode = match editor.current_mode {
EditorMode::Insert => true,
_ => false,
};
(character, (font_width, font_height).into(), in_insert_mode)
};
let destination: Point = (grid_x as f32 * font_width, grid_y as f32 * font_height).into();
@ -311,8 +321,14 @@ impl CursorRenderer {
if !center_destination.is_zero() {
for corner in self.corners.iter_mut() {
let corner_animating =
corner.update(&settings, font_dimensions, center_destination, dt);
let corner_animating = corner.update(
&settings,
font_dimensions,
center_destination,
dt,
!settings.animate_in_insert_mode && in_insert_mode,
);
animating |= corner_animating;
}
@ -336,23 +352,29 @@ impl CursorRenderer {
// The cursor is made up of four points, so I create a path with each of the four
// corners.
let mut path = Path::new();
path.move_to(self.corners[0].current_position);
path.line_to(self.corners[1].current_position);
path.line_to(self.corners[2].current_position);
path.line_to(self.corners[3].current_position);
path.close();
canvas.draw_path(&path, &paint);
// Draw foreground
paint.set_color(cursor.foreground(&default_colors).to_color());
canvas.save();
canvas.clip_path(&path, None, Some(false));
let blobs = &shaper.shape_cached(&character, false, false);
for blob in blobs.iter() {
canvas.draw_text_blob(&blob, destination, &paint);
}
canvas.restore();
if let Some(vfx) = self.cursor_vfx.as_ref() {
vfx.render(
&settings,

@ -215,6 +215,7 @@ impl Renderer {
&default_style,
);
}
for command in draw_commands.iter() {
self.draw_foreground(
&mut canvas,
@ -234,10 +235,10 @@ impl Renderer {
window_size.width as f32,
window_size.height as f32,
);
gpu_canvas.draw_image_rect(image, None, &image_destination, &self.paint);
self.surface = Some(surface);
self.cursor_renderer.draw(
cursor,
&default_style.colors,

@ -206,6 +206,7 @@ impl Settings {
pub async fn read_initial_values(&self, nvim: &Neovim<Compat<ChildStdin>>) {
let keys: Vec<String> = self.listeners.read().keys().cloned().collect();
for name in keys {
let variable_name = format!("neovide_{}", name.to_string());
match nvim.get_var(&variable_name).await {
@ -223,6 +224,7 @@ impl Settings {
pub async fn setup_changed_listeners(&self, nvim: &Neovim<Compat<ChildStdin>>) {
let keys: Vec<String> = self.listeners.read().keys().cloned().collect();
for name in keys {
let vimscript = format!(
concat!(

@ -6,6 +6,7 @@ use log::{debug, error, info, trace};
use skulpin::sdl2;
use skulpin::sdl2::event::{Event, WindowEvent};
use skulpin::sdl2::keyboard::Keycode;
use skulpin::sdl2::video::FullscreenType;
use skulpin::sdl2::Sdl;
use skulpin::{
CoordinateSystem, LogicalSize, PhysicalSize, PresentMode, Renderer as SkulpinRenderer,
@ -55,7 +56,7 @@ struct WindowWrapper {
previous_size: LogicalSize,
transparency: f32,
fullscreen: bool,
cached_size: (i32, i32),
cached_size: (u32, u32),
cached_position: (i32, i32),
}
@ -97,6 +98,7 @@ pub fn window_geometry() -> Result<(u64, u64), String> {
.map_err(|msg| msg.to_owned())
})
}
pub fn window_geometry_or_default() -> (u64, u64) {
window_geometry().unwrap_or(INITIAL_DIMENSIONS)
}
@ -176,53 +178,60 @@ impl WindowWrapper {
}
pub fn toggle_fullscreen(&mut self) {
unsafe {
let raw_handle = self.window.raw();
let display_index = sdl2::sys::SDL_GetWindowDisplayIndex(raw_handle);
if let Ok(rect) = self.window.subsystem().display_bounds(display_index) {
if self.fullscreen {
// Set window back to resizable
if self.fullscreen {
if cfg!(target_os = "windows") {
unsafe {
let raw_handle = self.window.raw();
sdl2::sys::SDL_SetWindowResizable(raw_handle, sdl2::sys::SDL_bool::SDL_TRUE);
}
} else {
self.window.set_fullscreen(FullscreenType::Off).ok();
}
// Use cached size and position
self.window
.set_size(self.cached_size.0 as u32, self.cached_size.1 as u32)
.unwrap();
self.window.set_position(
sdl2::video::WindowPos::Positioned(self.cached_position.0),
sdl2::video::WindowPos::Positioned(self.cached_position.1),
);
self.window.set_bordered(true);
} else {
// Cache the size and position
sdl2::sys::SDL_GetWindowSize(
raw_handle,
&mut self.cached_size.0,
&mut self.cached_size.1,
);
sdl2::sys::SDL_GetWindowPosition(
raw_handle,
&mut self.cached_position.0,
&mut self.cached_position.1,
);
sdl2::sys::SDL_SetWindowResizable(raw_handle, sdl2::sys::SDL_bool::SDL_FALSE);
// Use cached size and position
self.window
.set_size(self.cached_size.0, self.cached_size.1)
.unwrap();
self.window.set_position(
sdl2::video::WindowPos::Positioned(self.cached_position.0),
sdl2::video::WindowPos::Positioned(self.cached_position.1),
);
} else {
self.cached_size = self.window.size();
self.cached_position = self.window.position();
if cfg!(target_os = "windows") {
let video_subsystem = self.window.subsystem();
if let Ok(rect) = self
.window
.display_index()
.and_then(|index| video_subsystem.display_bounds(index))
{
// Set window to fullscreen
unsafe {
let raw_handle = self.window.raw();
sdl2::sys::SDL_SetWindowResizable(
raw_handle,
sdl2::sys::SDL_bool::SDL_FALSE,
);
}
self.window.set_size(rect.width(), rect.height()).unwrap();
self.window.set_position(
sdl2::video::WindowPos::Positioned(rect.x()),
sdl2::video::WindowPos::Positioned(rect.y()),
);
self.window.set_bordered(true);
}
} else {
self.window.set_fullscreen(FullscreenType::Desktop).ok();
}
}
self.fullscreen = !self.fullscreen;
}
pub fn synchronize_settings(&mut self) {
let editor_title = { EDITOR.lock().title.clone() };
if self.title != editor_title {
self.title = editor_title;
self.window
@ -231,6 +240,7 @@ impl WindowWrapper {
}
let transparency = { SETTINGS.get::<WindowSettings>().transparency };
if let Ok(opacity) = self.window.opacity() {
if opacity != transparency {
self.window.set_opacity(transparency).ok();
@ -239,6 +249,7 @@ impl WindowWrapper {
}
let fullscreen = { SETTINGS.get::<WindowSettings>().fullscreen };
if self.fullscreen != fullscreen {
self.toggle_fullscreen();
}
@ -353,9 +364,12 @@ impl WindowWrapper {
}
debug!("Render Triggered");
let current_size = self.previous_size;
if REDRAW_SCHEDULER.should_draw() || SETTINGS.get::<WindowSettings>().no_idle {
let renderer = &mut self.renderer;
if self
.skulpin_renderer
.draw(&sdl_window_wrapper, |canvas, coordinate_system_helper| {
@ -371,6 +385,7 @@ impl WindowWrapper {
return false;
}
}
return true;
}
}
@ -409,6 +424,7 @@ pub fn ui_loop() {
.context
.event_pump()
.expect("Could not create sdl event pump");
loop {
let frame_start = Instant::now();

Loading…
Cancel
Save