Skip to content

Commit

Permalink
Implement drag scroll, fixes #154
Browse files Browse the repository at this point in the history
  • Loading branch information
jackpot51 committed Feb 5, 2025
1 parent f4ef25e commit 04f2812
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 54 deletions.
32 changes: 30 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use cosmic::{
cosmic_theme, executor,
font::Font,
iced::{
self,
advanced::graphics::text::font_system,
clipboard, event,
futures::{self, SinkExt},
Expand Down Expand Up @@ -318,6 +319,7 @@ enum NewTab {
#[derive(Clone, Debug)]
pub enum Message {
AppTheme(AppTheme),
AutoScroll(Option<f32>),
Config(Config),
ConfigState(ConfigState),
CloseFile,
Expand Down Expand Up @@ -374,6 +376,7 @@ pub enum Message {
SaveAll,
SaveAsDialog(Option<segmented_button::Entity>),
SaveAsResult(segmented_button::Entity, DialogResult),
Scroll(f32),
SelectAll,
SystemThemeModeChange(cosmic_theme::ThemeMode),
SyntaxTheme(usize, bool),
Expand Down Expand Up @@ -438,6 +441,7 @@ pub struct App {
theme_names: Vec<String>,
context_page: ContextPage,
text_box_id: widget::Id,
auto_scroll: Option<f32>,
dialog_opt: Option<Dialog<Message>>,
dialog_page_opt: Option<DialogPage>,
find_opt: Option<bool>,
Expand Down Expand Up @@ -1323,6 +1327,7 @@ impl Application for App {
theme_names,
context_page: ContextPage::Settings,
text_box_id: widget::Id::unique(),
auto_scroll: None,
dialog_opt: None,
dialog_page_opt: None,
find_opt: None,
Expand Down Expand Up @@ -1566,6 +1571,9 @@ impl Application for App {
self.config.app_theme = app_theme;
return self.save_config();
}
Message::AutoScroll(auto_scroll) => {
self.auto_scroll = auto_scroll;
}
Message::Config(config) => {
if config != self.config {
log::info!("update config");
Expand Down Expand Up @@ -2330,6 +2338,16 @@ impl Application for App {
editor.set_selection(selection);
}
}
Message::Scroll(auto_scroll) => {
if let Some(Tab::Editor(tab)) = self.active_tab_mut() {
let mut editor = tab.editor.lock().unwrap();
editor.with_buffer_mut(|buffer| {
let mut scroll = buffer.scroll();
scroll.vertical += auto_scroll;
buffer.set_scroll(scroll);
});
}
}
Message::SystemThemeModeChange(_theme_mode) => {
return self.update_config();
}
Expand Down Expand Up @@ -2687,6 +2705,7 @@ impl Application for App {
Some(Tab::Editor(tab)) => {
let mut text_box = text_box(&tab.editor, self.config.metrics())
.id(self.text_box_id.clone())
.on_auto_scroll(Message::AutoScroll)
.on_changed(Message::TabChanged(tab_id))
.has_context_menu(tab.context_menu.is_some())
.on_context_menu(move |position_opt| {
Expand Down Expand Up @@ -2928,7 +2947,7 @@ impl Application for App {
struct ConfigStateSubscription;
struct ThemeSubscription;

Subscription::batch([
let mut subscriptions = vec![
event::listen_with(|event, status, window_id| match event {
event::Event::Keyboard(keyboard::Event::KeyPressed { modifiers, key, .. }) => {
match status {
Expand Down Expand Up @@ -3046,6 +3065,15 @@ impl Application for App {
Some(dialog) => dialog.subscription(),
None => Subscription::none(),
},
])
];

if let Some(auto_scroll) = self.auto_scroll {
subscriptions.push(
iced::time::every(time::Duration::from_millis(10))
.map(move |_| Message::Scroll(auto_scroll)),
);
}

Subscription::batch(subscriptions)
}
}
108 changes: 56 additions & 52 deletions src/tab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@ use cosmic_text::{Attrs, Buffer, Cursor, Edit, Selection, Shaping, SyntaxEditor,
use notify::Watcher;
use regex::Regex;
use std::{
io::Write,
fs,
io::Write,
path::PathBuf,
process::{Command, Stdio},
sync::{Arc, Mutex},
};


use crate::{fl, git::GitDiff, Config, SYNTAX_SYSTEM};

pub enum Tab {
Expand Down Expand Up @@ -147,65 +146,70 @@ impl EditorTab {
}

pub fn save(&mut self) {
if let Some(path) = &self.path_opt {
let mut editor = self.editor.lock().unwrap();
let mut text = String::new();

editor.with_buffer(|buffer| {
for line in buffer.lines.iter() {
text.push_str(line.text());
text.push_str(line.ending().as_str());
}
});
if let Some(path) = &self.path_opt {
let mut editor = self.editor.lock().unwrap();
let mut text = String::new();

match fs::write(path, &text) {
Ok(()) => {
editor.save_point();
log::info!("saved {:?}", path);
}
Err(err) => {
if err.kind() == std::io::ErrorKind::PermissionDenied {
log::warn!("Permission denied. Attempting to save with pkexec.");

if let Ok(mut output) = Command::new("pkexec")
.arg("tee")
.arg(path)
.stdin(Stdio::piped())
.stdout(Stdio::null()) // Redirect stdout to /dev/null
.stderr(Stdio::inherit()) // Retain stderr for error visibility
.spawn()
{
if let Some(mut stdin) = output.stdin.take() {
if let Err(e) = stdin.write_all(text.as_bytes()) {
log::error!("Failed to write to stdin: {}", e);
}
} else {
log::error!("Failed to access stdin of pkexec process.");
}
editor.with_buffer(|buffer| {
for line in buffer.lines.iter() {
text.push_str(line.text());
text.push_str(line.ending().as_str());
}
});

// Ensure the child process is reaped
match output.wait() {
Ok(status) => {
if status.success() {
// Mark the editor's state as saved if the process succeeds
editor.save_point();
log::info!("File saved successfully with pkexec.");
} else {
log::error!("pkexec process exited with a non-zero status: {:?}", status);
match fs::write(path, &text) {
Ok(()) => {
editor.save_point();
log::info!("saved {:?}", path);
}
Err(err) => {
if err.kind() == std::io::ErrorKind::PermissionDenied {
log::warn!("Permission denied. Attempting to save with pkexec.");

if let Ok(mut output) = Command::new("pkexec")
.arg("tee")
.arg(path)
.stdin(Stdio::piped())
.stdout(Stdio::null()) // Redirect stdout to /dev/null
.stderr(Stdio::inherit()) // Retain stderr for error visibility
.spawn()
{
if let Some(mut stdin) = output.stdin.take() {
if let Err(e) = stdin.write_all(text.as_bytes()) {
log::error!("Failed to write to stdin: {}", e);
}
} else {
log::error!("Failed to access stdin of pkexec process.");
}
Err(e) => {
log::error!("Failed to wait on pkexec process: {}", e);

// Ensure the child process is reaped
match output.wait() {
Ok(status) => {
if status.success() {
// Mark the editor's state as saved if the process succeeds
editor.save_point();
log::info!("File saved successfully with pkexec.");
} else {
log::error!(
"pkexec process exited with a non-zero status: {:?}",
status
);
}
}
Err(e) => {
log::error!("Failed to wait on pkexec process: {}", e);
}
}
} else {
log::error!(
"Failed to spawn pkexec process. Check permissions or path."
);
}
} else {
log::error!("Failed to spawn pkexec process. Check permissions or path.");
}
}
}
}
} else {
log::warn!("tab has no path yet");
} else {
log::warn!("tab has no path yet");
}
}

Expand Down
24 changes: 24 additions & 0 deletions src/text_box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub struct TextBox<'a, Message> {
metrics: Metrics,
id: Option<Id>,
padding: Padding,
on_auto_scroll: Option<Box<dyn Fn(Option<f32>) -> Message + 'a>>,
on_changed: Option<Message>,
click_timing: Duration,
has_context_menu: bool,
Expand All @@ -60,6 +61,7 @@ where
metrics,
id: None,
padding: Padding::new(0.0),
on_auto_scroll: None,
on_changed: None,
click_timing: Duration::from_millis(500),
has_context_menu: false,
Expand All @@ -79,6 +81,11 @@ where
self
}

pub fn on_auto_scroll(mut self, on_auto_scroll: impl Fn(Option<f32>) -> Message + 'a) -> Self {
self.on_auto_scroll = Some(Box::new(on_auto_scroll));
self
}

pub fn on_changed(mut self, on_changed: Message) -> Self {
self.on_changed = Some(on_changed);
self
Expand Down Expand Up @@ -1109,6 +1116,9 @@ where
Event::Mouse(MouseEvent::ButtonReleased(Button::Left)) => {
state.dragging = None;
status = Status::Captured;
if let Some(on_auto_scroll) = &self.on_auto_scroll {
shell.publish(on_auto_scroll(None));
}
}
Event::Mouse(MouseEvent::CursorMoved { .. }) => {
if let Some(dragging) = &state.dragging {
Expand All @@ -1124,6 +1134,20 @@ where
x: x as i32,
y: y as i32,
});
let auto_scroll = editor.with_buffer(|buffer| {
//TODO: ideal auto scroll speed
let speed = 10.0;
if y < 0.0 {
Some(y * speed)
} else if y > buffer.size().1.unwrap_or(0.0) {
Some((y - buffer.size().1.unwrap_or(0.0)) * speed)
} else {
None
}
});
if let Some(on_auto_scroll) = &self.on_auto_scroll {
shell.publish(on_auto_scroll(auto_scroll));
}
}
Dragging::ScrollbarV {
start_y,
Expand Down

0 comments on commit 04f2812

Please sign in to comment.