summaryrefslogtreecommitdiffstats
path: root/src/browser_states.rs
diff options
context:
space:
mode:
authorCanop <cano.petrole@gmail.com>2019-07-19 14:22:59 +0200
committerCanop <cano.petrole@gmail.com>2019-07-19 14:22:59 +0200
commitec657ff1ec83b7f9a6496f2a51e2c32e8ba6d0cc (patch)
treee4f13fb346dde5587b71bca98b97ed5dbd1c0adb /src/browser_states.rs
parentf3291c3e7a13c3d1867c7b1e2afbc3c3084c4246 (diff)
change the behavior of open and alt-open on standard files
The logic behind opening has changed to allow easier opening of files in non terminal applications without closing broot. **Old behavior:** - in case of enter or double-click - on a directory: open that directory, staying in broot - on a file: open the file, quitting broot - in case of alt-enter - on a directory: cd to that directory, quitting broot - on a file: cd to that file's parent directory, quitting broot **New behavior:** - in case of enter or double-click - on a directory: open that directory, staying in broot - on a file: open that file in default editor, not closing broot - in case of alt-enter - on a directory: cd to that directory, quitting broot - on a file: open that file in default editor, quitting broot
Diffstat (limited to 'src/browser_states.rs')
-rw-r--r--src/browser_states.rs116
1 files changed, 80 insertions, 36 deletions
diff --git a/src/browser_states.rs b/src/browser_states.rs
index 5e1aecf..04b5e86 100644
--- a/src/browser_states.rs
+++ b/src/browser_states.rs
@@ -4,6 +4,8 @@ use std::result::Result;
use std::time::Instant;
use std::fs::OpenOptions;
+use opener;
+
use crate::app::{AppState, AppStateCmdResult};
use crate::app_context::AppContext;
use crate::commands::{Action, Command};
@@ -84,17 +86,18 @@ impl BrowserState {
self.filtered_tree.as_mut().unwrap_or(&mut self.tree)
}
- fn open_selection(
+ fn open_selection_stay_in_broot(
&mut self,
screen: &mut Screen,
- con: &AppContext,
+ _con: &AppContext,
) -> io::Result<AppStateCmdResult> {
let tree = self.displayed_tree();
let line = tree.selected_line();
let tl = TaskLifetime::unlimited();
match &line.line_type {
LineType::File => {
- opener(line.path.clone(), line.is_exe(), con)
+ opener::open(&line.path).unwrap();
+ Ok(AppStateCmdResult::Keep)
}
LineType::Dir | LineType::SymLinkToDir(_) => {
let mut target = line.target();
@@ -116,7 +119,39 @@ impl BrowserState {
))
}
LineType::SymLinkToFile(target) => {
- opener(
+ let path = PathBuf::from(target);
+ opener::open(&path).unwrap();
+ Ok(AppStateCmdResult::Keep)
+ }
+ _ => {
+ unreachable!();
+ }
+ }
+ }
+
+ fn open_selection_quit_broot(
+ &mut self,
+ screen: &mut Screen,
+ con: &AppContext,
+ ) -> io::Result<AppStateCmdResult> {
+ let tree = self.displayed_tree();
+ let line = tree.selected_line();
+ match &line.line_type {
+ LineType::File => {
+ make_opener(line.path.clone(), line.is_exe(), con)
+ }
+ LineType::Dir | LineType::SymLinkToDir(_) => {
+ if con.launch_args.cmd_export_path.is_some() {
+ let cd_idx = con.verb_store.index_of("cd");
+ con.verb_store.verbs[cd_idx].to_cmd_result(&line.target(), &None, screen, con)
+ } else {
+ Ok(AppStateCmdResult::DisplayError(
+ "This feature needs broot to be launched with the `br` script".to_owned()
+ ))
+ }
+ }
+ LineType::SymLinkToFile(target) => {
+ make_opener(
PathBuf::from(target),
line.is_exe(), // today this always return false
con,
@@ -128,9 +163,40 @@ impl BrowserState {
}
}
+ fn write_status_normal(&self, screen: &mut Screen, has_pattern: bool) -> io::Result<()> {
+ let tree = self.displayed_tree();
+ screen.write_status_text(
+ if tree.selection == 0 {
+ if has_pattern {
+ "Hit <esc> to go back, <enter> to go up, '?' for help, or a few letters to search"
+ } else {
+ "Hit <esc> to remove the filter, <enter> to go up, '?' for help"
+ }
+ } else {
+ let line = &tree.lines[tree.selection];
+ if has_pattern {
+ if line.is_dir() {
+ "Hit <enter> to focus, <alt><enter> to cd, <esc> to remove the filter, or a space then a verb"
+ } else {
+ "Hit <enter> to open, <alt><enter> to open and quit, <esc> to clear the filter, or a space then a verb"
+ }
+ } else {
+ if line.is_dir() {
+ "Hit <enter> to focus, <alt><enter> to cd, or a space then a verb"
+ } else {
+ "Hit <enter> to open the file, <alt><enter> to open and quit, or type a space then a verb"
+ }
+ }
+ }
+ )
+ }
+
}
-fn opener(path: PathBuf, is_exe: bool, con: &AppContext) -> io::Result<AppStateCmdResult> {
+/// build a AppStateCmdResult with a launchable which will be used to
+/// 1/ quit broot
+/// 2/ open the relevant file the best possible way
+fn make_opener(path: PathBuf, is_exe: bool, con: &AppContext) -> io::Result<AppStateCmdResult> {
Ok(
if is_exe {
let path = path.to_string_lossy().to_string();
@@ -190,7 +256,7 @@ impl AppState for BrowserState {
}
Action::DoubleClick(_, y) => {
if self.displayed_tree().selection + 1 == *y as usize {
- self.open_selection(screen, con)
+ self.open_selection_stay_in_broot(screen, con)
} else {
// A double click always come after a simple click at
// same position. If it's not the selected line, it means
@@ -198,12 +264,8 @@ impl AppState for BrowserState {
Ok(AppStateCmdResult::Keep)
}
}
- Action::OpenSelection => self.open_selection(screen, con),
- Action::AltOpenSelection => {
- let line = self.displayed_tree().selected_line();
- let cd_idx = con.verb_store.index_of("cd");
- con.verb_store.verbs[cd_idx].to_cmd_result(&line.target(), &None, screen, con)
- }
+ Action::OpenSelection => self.open_selection_stay_in_broot(screen, con),
+ Action::AltOpenSelection => self.open_selection_quit_broot(screen, con),
Action::Verb(invocation) => match con.verb_store.search(&invocation.key) {
PrefixSearchResult::Match(verb) => {
self.execute_verb(verb, &invocation, screen, con)
@@ -312,18 +374,15 @@ impl AppState for BrowserState {
Ok(())
}
+
fn write_status(&self, screen: &mut Screen, cmd: &Command, con: &AppContext) -> io::Result<()> {
match &cmd.action {
- Action::FuzzyPatternEdit(s) if s.len() > 0 => {
- screen.write_status_text("Hit <enter> to select, <esc> to remove the filter")
- }
- Action::RegexEdit(s, _) if s.len() > 0 => {
- screen.write_status_text("Hit <enter> to select, <esc> to remove the filter")
- }
+ Action::FuzzyPatternEdit(s) if s.len() > 0 => self.write_status_normal(screen, true),
+ Action::RegexEdit(s, _) if s.len() > 0 => self.write_status_normal(screen, true),
Action::VerbEdit(invocation) => {
match con.verb_store.search(&invocation.key) {
PrefixSearchResult::NoMatch => {
- screen.write_status_err("No matching verb (':?' for the list of verbs)")
+ screen.write_status_err("No matching verb ('?' for the list of verbs)")
}
PrefixSearchResult::Match(verb) => {
if let Some(err) = verb.match_error(invocation) {
@@ -341,26 +400,11 @@ impl AppState for BrowserState {
}
}
PrefixSearchResult::TooManyMatches => screen.write_status_text(
- // TODO show what verbs start with the currently edited verb key
- "Type a verb then <enter> to execute it (':?' for the list of verbs)",
+ "Type a verb then <enter> to execute it ('?' for the list of verbs)",
),
}
}
- _ => {
- let tree = self.displayed_tree();
- if tree.selection == 0 {
- screen.write_status_text(
- "Hit <esc> to go back, <enter> to go up, '?' for help, or a few letters to search",
- )
- } else {
- let line = &tree.lines[tree.selection];
- screen.write_status_text(if line.is_dir() {
- "Hit <enter> to focus, <alt><enter> to cd, or a space then a verb"
- } else {
- "Hit <enter> to open the file, or type a space then a verb"
- })
- }
- }
+ _ => self.write_status_normal(screen, false),
}
}
a> 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847
/*
 *  Copyright (C) 1995-1996  Linus Torvalds & authors (see below)
 */

/*
 *  Original authors:	abramov@cecmow.enet.dec.com (Igor Abramov)
 *			mlord@pobox.com (Mark Lord)
 *
 *  See linux/MAINTAINERS for address of current maintainer.
 *
 *  This file provides support for the advanced features and bugs
 *  of IDE interfaces using the CMD Technologies 0640 IDE interface chip.
 *
 *  These chips are basically fucked by design, and getting this driver
 *  to work on every motherboard design that uses this screwed chip seems
 *  bloody well impossible.  However, we're still trying.
 *
 *  Version 0.97 worked for everybody.
 *
 *  User feedback is essential.  Many thanks to the beta test team:
 *
 *  A.Hartgers@stud.tue.nl, JZDQC@CUNYVM.CUNY.edu, abramov@cecmow.enet.dec.com,
 *  bardj@utopia.ppp.sn.no, bart@gaga.tue.nl, bbol001@cs.auckland.ac.nz,
 *  chrisc@dbass.demon.co.uk, dalecki@namu26.Num.Math.Uni-Goettingen.de,
 *  derekn@vw.ece.cmu.edu, florian@btp2x3.phy.uni-bayreuth.de,
 *  flynn@dei.unipd.it, gadio@netvision.net.il, godzilla@futuris.net,
 *  j@pobox.com, jkemp1@mises.uni-paderborn.de, jtoppe@hiwaay.net,
 *  kerouac@ssnet.com, meskes@informatik.rwth-aachen.de, hzoli@cs.elte.hu,
 *  peter@udgaard.isgtec.com, phil@tazenda.demon.co.uk, roadcapw@cfw.com,
 *  s0033las@sun10.vsz.bme.hu, schaffer@tam.cornell.edu, sjd@slip.net,
 *  steve@ei.org, ulrpeg@bigcomm.gun.de, ism@tardis.ed.ac.uk, mack@cray.com
 *  liug@mama.indstate.edu, and others.
 *
 *  Version 0.01	Initial version, hacked out of ide.c,
 *			and #include'd rather than compiled separately.
 *			This will get cleaned up in a subsequent release.
 *
 *  Version 0.02	Fixes for vlb initialization code, enable prefetch
 *			for versions 'B' and 'C' of chip by default,
 *			some code cleanup.
 *
 *  Version 0.03	Added reset of secondary interface,
 *			and black list for devices which are not compatible
 *			with prefetch mode. Separate function for setting
 *			prefetch is added, possibly it will be called some
 *			day from ioctl processing code.
 *
 *  Version 0.04	Now configs/compiles separate from ide.c
 *
 *  Version 0.05	Major rewrite of interface timing code.
 *			Added new function cmd640_set_mode to set PIO mode
 *			from ioctl call. New drives added to black list.
 *
 *  Version 0.06	More code cleanup. Prefetch is enabled only for
 *			detected hard drives, not included in prefetch
 *			black list.
 *
 *  Version 0.07	Changed to more conservative drive tuning policy.
 *			Unknown drives, which report PIO < 4 are set to
 *			(reported_PIO - 1) if it is supported, or to PIO0.
 *			List of known drives extended by info provided by
 *			CMD at their ftp site.
 *
 *  Version 0.08	Added autotune/noautotune support.
 *
 *  Version 0.09	Try to be smarter about 2nd port enabling.
 *  Version 0.10	Be nice and don't reset 2nd port.
 *  Version 0.11	Try to handle more weird situations.
 *
 *  Version 0.12	Lots of bug fixes from Laszlo Peter
 *			irq unmasking disabled for reliability.
 *			try to be even smarter about the second port.
 *			tidy up source code formatting.
 *  Version 0.13	permit irq unmasking again.
 *  Version 0.90	massive code cleanup, some bugs fixed.
 *			defaults all drives to PIO mode0, prefetch off.
 *			autotune is OFF by default, with compile time flag.
 *			prefetch can be turned OFF/ON using "hdparm -p8/-p9"
 *			 (requires hdparm-3.1 or newer)
 *  Version 0.91	first release to linux-kernel list.
 *  Version 0.92	move initial reg dump to separate callable function
 *			change "readahead" to "prefetch" to avoid confusion
 *  Version 0.95	respect original BIOS timings unless autotuning.
 *			tons of code cleanup and rearrangement.
 *			added CONFIG_BLK_DEV_CMD640_ENHANCED option
 *			prevent use of unmask when prefetch is on
 *  Version 0.96	prevent use of io_32bit when prefetch is off
 *  Version 0.97	fix VLB secondary interface for sjd@slip.net
 *			other minor tune-ups:  0.96 was very good.
 *  Version 0.98	ignore PCI version when disabled by BIOS
 *  Version 0.99	display setup/active/recovery clocks with PIO mode
 *  Version 1.00	Mmm.. cannot depend on PCMD_ENA in all systems
 *  Version 1.01	slow/fast devsel can be selected with "hdparm -p6/-p7"
 *			 ("fast" is necessary for 32bit I/O in some systems)
 *  Version 1.02	fix bug that resulted in slow "setup times"
 *			 (patch courtesy of Zoltan Hidvegi)
 */

#define CMD640_PREFETCH_MASKS 1

/*#define CMD640_DUMP_REGS */

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>

#include <asm/io.h>

#define DRV_NAME "cmd640"

static bool cmd640_vlb;

/*
 * CMD640 specific registers definition.
 */

#define VID		0x00
#define DID		0x02
#define PCMD		0x04
#define   PCMD_ENA	0x01
#define PSTTS		0x06
#define REVID		0x08
#define PROGIF		0x09
#define SUBCL		0x0a
#define BASCL		0x0b
#define BaseA0		0x10
#define BaseA1		0x14
#define BaseA2		0x18
#define BaseA3		0x1c
#define INTLINE		0x3c
#define INPINE		0x3d

#define	CFR		0x50
#define   CFR_DEVREV		0x03
#define   CFR_IDE01INTR		0x04
#define	  CFR_DEVID		0x18
#define	  CFR_AT_VESA_078h	0x20
#define	  CFR_DSA1		0x40
#define	  CFR_DSA0		0x80

#define CNTRL		0x51
#define	  CNTRL_DIS_RA0		0x40
#define   CNTRL_DIS_RA1		0x80
#define	  CNTRL_ENA_2ND		0x08

#define	CMDTIM		0x52
#define	ARTTIM0		0x53
#define	DRWTIM0		0x54
#define ARTTIM1 	0x55
#define DRWTIM1		0x56
#define ARTTIM23	0x57
#define   ARTTIM23_DIS_RA2	0x04
#define   ARTTIM23_DIS_RA3	0x08
#define   ARTTIM23_IDE23INTR	0x10
#define DRWTIM23	0x58
#define BRST		0x59

/*
 * Registers and masks for easy access by drive index:
 */
static u8 prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
static u8 prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};

#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED

static u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
static u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM23, DRWTIM23};

/*
 * Current cmd640 timing values for each drive.
 * The defaults for each are the slowest possible timings.
 */
static u8 setup_counts[4]    = {4, 4, 4, 4};     /* Address setup count (in clocks) */
static u8 active_counts[4]   = {16, 16, 16, 16}; /* Active count   (encoded) */
static u8 recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */

#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */

static DEFINE_SPINLOCK(cmd640_lock);

/*
 * Interface to access cmd640x registers
 */
static unsigned int cmd640_key;
static void (*__put_cmd640_reg)(u16 reg, u8 val);
static u8 (*__get_cmd640_reg)(u16 reg);

/*
 * This is read from the CFR reg, and is used in several places.
 */
static unsigned int cmd640_chip_version;

/*
 * The CMD640x chip does not support DWORD config write cycles, but some
 * of the BIOSes use them to implement the config services.
 * Therefore, we must use direct IO instead.
 */

/* PCI method 1 access */

static void put_cmd640_reg_pci1(u16 reg, u8 val)
{
	outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
	outb_p(val, (reg & 3) | 0xcfc);
}

static u8 get_cmd640_reg_pci1(u16 reg)
{
	outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
	return inb_p((reg & 3) | 0xcfc);
}

/* PCI method 2 access (from CMD datasheet) */

static void put_cmd640_reg_pci2(u16 reg, u8 val)
{
	outb_p(0x10, 0xcf8);
	outb_p(val, cmd640_key + reg);
	outb_p(0, 0xcf8);
}

static u8 get_cmd640_reg_pci2(u16 reg)
{
	u8 b;

	outb_p(0x10, 0xcf8);
	b = inb_p(cmd640_key + reg);
	outb_p(0, 0xcf8);
	return b;
}

/* VLB access */

static void put_cmd640_reg_vlb(u16 reg, u8 val)
{
	outb_p(reg, cmd640_key);
	outb_p(val, cmd640_key + 4);
}

static u8 get_cmd640_reg_vlb(u16 reg)
{
	outb_p(reg, cmd640_key);
	return inb_p(cmd640_key + 4);
}

static u8 get_cmd640_reg(u16 reg)
{
	unsigned long flags;
	u8 b;

	spin_lock_irqsave(&cmd640_lock, flags);
	b = __get_cmd640_reg(reg);
	spin_unlock_irqrestore(&cmd640_lock, flags);
	return b;
}

static void put_cmd640_reg(u16 reg, u8 val)
{
	unsigned long flags;

	spin_lock_irqsave(&cmd640_lock, flags);
	__put_cmd640_reg(reg, val);
	spin_unlock_irqrestore(&cmd640_lock, flags);
}

static int __init match_pci_cmd640_device(void)
{
	const u8 ven_dev[4] = {0x95, 0x10, 0x40, 0x06};
	unsigned int i;
	for (i = 0; i < 4; i++) {
		if (get_cmd640_reg(i) != ven_dev