Skip to content

Commit

Permalink
feat(platform): windows version (#74)
Browse files Browse the repository at this point in the history
* init checkin

* tests now compile

* Update linux.rs

* fixed linux build

* fmt

* most tests pass

* all tests pass

* reinstate delete after test

* remove old snaps

* oops on the crossterm dep

* fix fmt

* add windows test to travis

* travis windows tests linux messed up term after q

* fmt

* clean as per PR

* more pr clean

* tests done on windows

* oops

* non windows tests

* more cleanup

* fmt

* one last clean

* linux->unix

* linux->unix

* style(cleanup): minor fixes

* style(cleanup): moar minor fixes

Co-authored-by: Aram Drevekenin <aram@poor.dev>
  • Loading branch information
pm100 and imsnif authored Sep 23, 2020
1 parent e6188b6 commit 929f759
Show file tree
Hide file tree
Showing 27 changed files with 748 additions and 604 deletions.
6 changes: 6 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
os:
- linux
- osx
- windows
language: rust
rust:
- stable
Expand All @@ -22,6 +23,11 @@ matrix:
rust: nightly
before_script:
- rustup component add rustfmt
- os: windows
rust: nightly
before_script:
- rustup component add rustfmt

allow_failures:
- rust: nightly

176 changes: 133 additions & 43 deletions Cargo.lock

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@ license = "MIT"
edition = "2018"

[dependencies]
tui = "0.9"
termion = "1.5"
tui = {version="0.11", default-features = false, features = ['crossterm'] }
crossterm = "0.17"
failure = "0.1"
jwalk = "0.5"
signal-hook = "0.1.10"
structopt = "0.3"
filesize = "0.2.0"
unicode-width = "0.1.7"
nix = "0.17.0"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["securitybaseapi","debugapi"] }

[dev-dependencies]
insta = "0.16.0"
46 changes: 28 additions & 18 deletions src/input/controls.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,44 @@
use ::std::io::stdin;
use ::termion::event::Event;
use ::termion::event::Key;
use ::termion::input::TermRead;
use ::tui::backend::Backend;
use crossterm::event::Event;
use crossterm::event::KeyModifiers;
use crossterm::event::{read, KeyCode, KeyEvent};

use crate::state::FileToDelete;
use crate::App;

#[derive(Clone)]
pub struct KeyboardEvents;
pub struct TerminalEvents;

impl Iterator for KeyboardEvents {
impl Iterator for TerminalEvents {
type Item = Event;
fn next(&mut self) -> Option<Event> {
match stdin().events().next() {
Some(Ok(ev)) => Some(ev),
_ => None,
}
Some(read().unwrap())
}
}

macro_rules! key {
(char $x:expr) => {
Event::Key(Key::Char($x))
Event::Key(KeyEvent {
code: KeyCode::Char($x),
modifiers: KeyModifiers::NONE,
})
};
(shift $x:expr) => {
Event::Key(KeyEvent {
code: KeyCode::Char($x),
modifiers: KeyModifiers::SHIFT,
})
};
(ctrl $x:expr) => {
Event::Key(Key::Ctrl($x))
Event::Key(KeyEvent {
code: KeyCode::Char($x),
modifiers: KeyModifiers::CONTROL,
})
};
($x:ident) => {
Event::Key(Key::$x)
Event::Key(KeyEvent {
code: KeyCode::$x,
modifiers: KeyModifiers::NONE,
})
};
}

Expand All @@ -49,7 +59,7 @@ pub fn handle_keypress_loading_mode<B: Backend>(evt: Event, app: &mut App<B>) {
key!(char 'k') | key!(Up) | key!(ctrl 'p') => {
app.move_selected_up();
}
key!(char '+') => {
key!(char '+') | key!(shift '+') => {
app.zoom_in();
}
key!(char '-') => {
Expand All @@ -58,7 +68,7 @@ pub fn handle_keypress_loading_mode<B: Backend>(evt: Event, app: &mut App<B>) {
key!(char '0') => {
app.reset_zoom();
}
key!(char '\n') => {
key!(char '\n') | key!(Enter) => {
app.handle_enter();
}
key!(Backspace) => {
Expand Down Expand Up @@ -91,7 +101,7 @@ pub fn handle_keypress_normal_mode<B: Backend>(evt: Event, app: &mut App<B>) {
key!(char 'k') | key!(Up) | key!(ctrl 'p') => {
app.move_selected_up();
}
key!(char '+') => {
key!(char '+') | key!(shift '+') => {
app.zoom_in();
}
key!(char '-') => {
Expand All @@ -100,7 +110,7 @@ pub fn handle_keypress_normal_mode<B: Backend>(evt: Event, app: &mut App<B>) {
key!(char '0') => {
app.reset_zoom();
}
key!(char '\n') => {
key!(char '\n') | key!(Enter) => {
app.handle_enter();
}
key!(Esc) => {
Expand Down
4 changes: 1 addition & 3 deletions src/input/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
mod controls;
mod signals;
pub mod controls;

pub use controls::*;
pub use signals::*;
23 changes: 0 additions & 23 deletions src/input/signals.rs

This file was deleted.

70 changes: 39 additions & 31 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod tests;
mod app;
mod input;
mod messages;
mod os;
mod state;
mod ui;

Expand All @@ -21,13 +22,15 @@ use ::std::sync::Arc;
use ::std::thread::park_timeout;
use ::std::{thread, time};
use ::structopt::StructOpt;
use ::termion::event::{Event as TermionEvent, Key};
use ::termion::raw::IntoRawMode;

use ::tui::backend::Backend;
use ::tui::backend::TermionBackend;
use crossterm::event::KeyModifiers;
use crossterm::event::{Event as BackEvent, KeyCode, KeyEvent};
use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
use tui::backend::CrosstermBackend;

use app::{App, UiMode};
use input::{sigwinch, KeyboardEvents};
use input::TerminalEvents;
use messages::{handle_events, Event, Instruction};

#[cfg(not(test))]
Expand Down Expand Up @@ -63,13 +66,18 @@ fn main() {
process::exit(2);
}
}
fn get_stdout() -> io::Result<io::Stdout> {
Ok(io::stdout())
}

fn try_main() -> Result<(), failure::Error> {
let opts = Opt::from_args();
match io::stdout().into_raw_mode() {

match get_stdout() {
Ok(stdout) => {
let terminal_backend = TermionBackend::new(stdout);
let keyboard_events = KeyboardEvents {};
enable_raw_mode()?;
let terminal_backend = CrosstermBackend::new(stdout);
let terminal_events = TerminalEvents {};
let folder = match opts.folder {
Some(folder) => folder,
None => env::current_dir()?,
Expand All @@ -79,28 +87,28 @@ fn try_main() -> Result<(), failure::Error> {
}
start(
terminal_backend,
Box::new(keyboard_events),
Box::new(terminal_events),
folder,
opts.apparent_size,
opts.disable_delete_confirmation,
);
}
Err(_) => failure::bail!("Failed to get stdout: are you trying to pipe 'diskonaut'?"),
}
disable_raw_mode()?;
Ok(())
}

pub fn start<B>(
terminal_backend: B,
keyboard_events: Box<dyn Iterator<Item = TermionEvent> + Send>,
terminal_events: Box<dyn Iterator<Item = BackEvent> + Send>,
path: PathBuf,
show_apparent_size: bool,
disable_delete_confirmation: bool,
) where
B: Backend + Send + 'static,
{
let mut active_threads = vec![];
let (on_sigwinch, cleanup) = sigwinch();

let (event_sender, event_receiver): (SyncSender<Event>, Receiver<Event>) =
mpsc::sync_channel(1);
Expand Down Expand Up @@ -129,10 +137,27 @@ pub fn start<B>(
let instruction_sender = instruction_sender.clone();
let running = running.clone();
move || {
for evt in keyboard_events {
if let TermionEvent::Key(Key::Char('y'))
| TermionEvent::Key(Key::Char('q'))
| TermionEvent::Key(Key::Ctrl('c')) = evt
for evt in terminal_events {
if let BackEvent::Resize(_x, _y) = evt {
if SHOULD_HANDLE_WIN_CHANGE {
let _ = instruction_sender.send(Instruction::ResetUiMode);
let _ = instruction_sender.send(Instruction::Render);
}
continue;
}

if let BackEvent::Key(KeyEvent {
code: KeyCode::Char('y'),
modifiers: KeyModifiers::NONE,
})
| BackEvent::Key(KeyEvent {
code: KeyCode::Char('q'),
modifiers: KeyModifiers::NONE,
})
| BackEvent::Key(KeyEvent {
code: KeyCode::Char('c'),
modifiers: KeyModifiers::CONTROL,
}) = evt
{
// not ideal, but works in a pinch
let _ = instruction_sender.send(Instruction::Keypress(evt));
Expand Down Expand Up @@ -220,22 +245,6 @@ pub fn start<B>(
);
}

if SHOULD_HANDLE_WIN_CHANGE {
active_threads.push(
thread::Builder::new()
.name("resize_handler".to_string())
.spawn({
move || {
on_sigwinch(Box::new(move || {
let _ = instruction_sender.send(Instruction::ResetUiMode);
let _ = instruction_sender.send(Instruction::Render);
}));
}
})
.unwrap(),
);
}

let mut app = App::new(
terminal_backend,
path,
Expand All @@ -245,7 +254,6 @@ pub fn start<B>(
);
app.start(instruction_receiver);
running.store(false, Ordering::Release);
cleanup();

for thread_handler in active_threads {
thread_handler.join().unwrap();
Expand Down
5 changes: 3 additions & 2 deletions src/messages/instruction.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use ::std::fs::Metadata;
use ::std::path::PathBuf;
use ::std::sync::mpsc::Receiver;
use ::termion::event::Event as TermionEvent;

use ::tui::backend::Backend;
use crossterm::event::Event as BackEvent;

use crate::input::{
handle_keypress_delete_file_mode, handle_keypress_error_message, handle_keypress_exiting_mode,
Expand All @@ -22,7 +23,7 @@ pub enum Instruction {
RenderAndUpdateBoard,
Render,
ResetUiMode,
Keypress(TermionEvent),
Keypress(BackEvent),
IncrementFailedToRead,
}

Expand Down
5 changes: 5 additions & 0 deletions src/os/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#[cfg(target_os = "windows")]
pub(crate) mod windows;

#[cfg(not(target_os = "windows"))]
pub(crate) mod unix;
5 changes: 5 additions & 0 deletions src/os/unix.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use nix::unistd::geteuid;

pub(crate) fn is_user_admin() -> bool {
geteuid().is_root()
}
41 changes: 41 additions & 0 deletions src/os/windows.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#[cfg(not(test))]
use winapi::um::winnt::{
DOMAIN_ALIAS_RID_ADMINS, PVOID, SECURITY_BUILTIN_DOMAIN_RID, SECURITY_NT_AUTHORITY,
SID_IDENTIFIER_AUTHORITY,
};

#[cfg(not(test))]
use winapi::um::securitybaseapi::{AllocateAndInitializeSid, CheckTokenMembership};
// https://stackoverflow.com/questions/4230602/detect-if-program-is-running-with-full-administrator-rights
#[cfg(not(test))]
pub(crate) fn is_user_admin() -> bool {
let mut auth_nt = SID_IDENTIFIER_AUTHORITY {
Value: SECURITY_NT_AUTHORITY,
};
let mut admingroup = 0 as PVOID;
let ismember = unsafe {
assert!(
AllocateAndInitializeSid(
&mut auth_nt,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0,
0,
0,
0,
0,
0,
&mut admingroup,
) != 0
);
let mut member: i32 = 0;
assert!(CheckTokenMembership(0 as PVOID, admingroup, &mut member) != 0);
member != 0
};
ismember
}
#[cfg(test)]
pub(crate) fn is_user_admin() -> bool {
false
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,6 @@ expression: "&terminal_draw_events_mirror[1]"



SELECTED: subfolder_with_quite_a_long_nam
subfolder_with_quite_a_long_name


Loading

0 comments on commit 929f759

Please sign in to comment.