diff --git a/Cargo.lock b/Cargo.lock
index 23ceae2..5d562cb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -185,6 +185,17 @@ dependencies = [
  "syn 1.0.30",
 ]
 
+[[package]]
+name = "confy"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2913470204e9e8498a0f31f17f90a0de801ae92c8c5ac18c49af4819e6786697"
+dependencies = [
+ "directories",
+ "serde",
+ "toml",
+]
+
 [[package]]
 name = "constant_time_eq"
 version = "0.1.5"
@@ -237,6 +248,16 @@ dependencies = [
  "generic-array",
 ]
 
+[[package]]
+name = "directories"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c"
+dependencies = [
+ "cfg-if",
+ "dirs-sys",
+]
+
 [[package]]
 name = "dirs"
 version = "1.0.5"
@@ -425,6 +446,7 @@ dependencies = [
  "ascii_table",
  "atty",
  "clap",
+ "confy",
  "itertools",
  "json",
  "mime",
@@ -434,6 +456,7 @@ dependencies = [
  "pest",
  "pest_derive",
  "regex",
+ "serde",
  "shlex",
  "thiserror",
  "url",
@@ -1506,6 +1529,15 @@ dependencies = [
  "tokio",
 ]
 
+[[package]]
+name = "toml"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a"
+dependencies = [
+ "serde",
+]
+
 [[package]]
 name = "tower-service"
 version = "0.3.0"
diff --git a/Cargo.toml b/Cargo.toml
index 082582c..097c5db 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -24,6 +24,8 @@ mime-db = "0.1.5"
 xdg-mime = { git = "https://github.com/ebassi/xdg-mime-rs" }
 atty = "0.2.14"
 notify-rust = "4.0.0-rc.1"
+confy = "0.4.0"
+serde = "1.0.111"
 
 [profile.release]
 opt-level=3
diff --git a/src/apps/user.rs b/src/apps/user.rs
index 5aacf4a..8306a59 100644
--- a/src/apps/user.rs
+++ b/src/apps/user.rs
@@ -1,4 +1,8 @@
-use crate::{apps::SystemApps, DesktopEntry, Error, Handler, Result};
+use crate::{
+    apps::SystemApps,
+    common::{DesktopEntry, Handler},
+    Error, Result,
+};
 use mime::Mime;
 use pest::Parser;
 use std::{
@@ -39,12 +43,28 @@ impl MimeApps {
         Ok(())
     }
     pub fn get_handler(&self, mime: &Mime) -> Result<Handler> {
-        self.default_apps
-            .get(mime)
-            .or_else(|| self.added_associations.get(mime))
-            .map(|hs| hs.get(0).unwrap().clone())
-            .or_else(|| self.system_apps.get_handler(mime))
-            .ok_or(Error::NotFound(mime.to_string()))
+        let config = crate::config::Config::load()?;
+
+        match self.default_apps.get(mime) {
+            Some(handlers) if config.enable_selector && handlers.len() > 1 => {
+                let handlers = handlers
+                    .into_iter()
+                    .map(|h| (h, h.get_entry().unwrap().name))
+                    .collect::<Vec<_>>();
+                let selected =
+                    config.select(handlers.iter().map(|h| h.1.clone()))?;
+                let selected =
+                    handlers.into_iter().find(|h| h.1 == selected).unwrap().0;
+                Ok(selected.clone())
+            }
+            Some(handlers) => Ok(handlers.get(0).unwrap().clone()),
+            None => self
+                .added_associations
+                .get(mime)
+                .map(|h| h.get(0).unwrap().clone())
+                .or_else(|| self.system_apps.get_handler(mime))
+                .ok_or(Error::NotFound(mime.to_string())),
+        }
     }
     pub fn show_handler(&self, mime: &Mime, output_json: bool) -> Result<()> {
         let handler = self.get_handler(mime)?;
diff --git a/src/cli.rs b/src/cli.rs
new file mode 100644
index 0000000..9c5be89
--- /dev/null
+++ b/src/cli.rs
@@ -0,0 +1,53 @@
+use crate::common::{Handler, MimeOrExtension};
+
+#[derive(clap::Clap)]
+#[clap(global_setting = clap::AppSettings::DeriveDisplayOrder)]
+#[clap(global_setting = clap::AppSettings::DisableHelpSubcommand)]
+#[clap(version = clap::crate_version!())]
+pub enum Cmd {
+    /// List default apps and the associated handlers
+    List,
+
+    /// Open a path/URL with its default handler
+    Open {
+        #[clap(required = true)]
+        paths: Vec<String>,
+    },
+
+    /// Set the default handler for mime/extension
+    Set {
+        mime: MimeOrExtension,
+        handler: Handler,
+    },
+
+    /// Unset the default handler for mime/extension
+    Unset { mime: MimeOrExtension },
+
+    /// Launch the handler for specified extension/mime with optional arguments
+    Launch {
+        mime: MimeOrExtension,
+        args: Vec<String>,
+    },
+
+    /// Get handler for this mime/extension
+    Get {
+        #[clap(long)]
+        json: bool,
+        mime: MimeOrExtension,
+    },
+
+    /// Add a handler for given mime/extension
+    /// Note that the first handler is the default
+    Add {
+        mime: MimeOrExtension,
+        handler: Handler,
+    },
+
+    #[clap(setting = clap::AppSettings::Hidden)]
+    Autocomplete {
+        #[clap(short)]
+        desktop_files: bool,
+        #[clap(short)]
+        mimes: bool,
+    },
+}
diff --git a/src/common/mime_types.rs b/src/common/mime_types.rs
index d12fdd3..5aa5bc3 100644
--- a/src/common/mime_types.rs
+++ b/src/common/mime_types.rs
@@ -8,9 +8,9 @@ use std::{
 
 // A mime derived from a path or URL
 #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
-pub struct FlexibleMime(pub Mime);
+pub struct MimeType(pub Mime);
 
-impl TryFrom<&str> for FlexibleMime {
+impl TryFrom<&str> for MimeType {
     type Error = Error;
 
     fn try_from(arg: &str) -> Result<Self> {
@@ -26,7 +26,7 @@ impl TryFrom<&str> for FlexibleMime {
     }
 }
 
-impl TryFrom<&Path> for FlexibleMime {
+impl TryFrom<&Path> for MimeType {
     type Error = Error;
     fn try_from(path: &Path) -> Result<Self> {
         let guess = SHARED_MIME_DB.guess_mime_type().path(path).guess();
@@ -47,7 +47,7 @@ impl FromStr for MimeOrExtension {
     type Err = Error;
     fn from_str(s: &str) -> Result<Self> {
         if s.starts_with(".") {
-            Ok(Self(FlexibleMime::try_from(s)?.0))
+            Ok(Self(MimeType::try_from(s)?.0))
         } else {
             Ok(Self(Mime::from_str(s)?))
         }
@@ -69,11 +69,11 @@ mod tests {
     #[test]
     fn from_path_with_extension() {
         assert_eq!(
-            FlexibleMime::try_from(".pdf").unwrap().0,
+            MimeType::try_from(".pdf").unwrap().0,
             mime::APPLICATION_PDF
         );
         assert_eq!(
-            FlexibleMime::try_from(".").unwrap().0.essence_str(),
+            MimeType::try_from(".").unwrap().0.essence_str(),
             "inode/directory"
         );
     }
diff --git a/src/common/mod.rs b/src/common/mod.rs
index 9568d8d..e1403f1 100644
--- a/src/common/mod.rs
+++ b/src/common/mod.rs
@@ -6,4 +6,4 @@ mod mime_types;
 pub use self::db::{autocomplete as db_autocomplete, SHARED_MIME_DB};
 pub use desktop_entry::{DesktopEntry, Rule as PestRule};
 pub use handler::Handler;
-pub use mime_types::{FlexibleMime, MimeOrExtension};
+pub use mime_types::{MimeOrExtension, MimeType};
diff --git a/src/config.rs b/src/config.rs
new file mode 100644
index 0000000..35b63b4
--- /dev/null
+++ b/src/config.rs
@@ -0,0 +1,55 @@
+use crate::Result;
+use serde::{Deserialize, Serialize};
+
+#[derive(Serialize, Deserialize)]
+pub struct Config {
+    pub enable_selector: bool,
+    pub selector: String,
+}
+
+impl Default for Config {
+    fn default() -> Self {
+        Config {
+            enable_selector: false,
+            selector: "rofi -dmenu".to_owned(),
+        }
+    }
+}
+
+impl Config {
+    pub fn load() -> Result<Self> {
+        Ok(confy::load("handlr")?)
+    }
+
+    pub fn select<O: Iterator<Item = String>>(
+        &self,
+        mut opts: O,
+    ) -> Result<String> {
+        use itertools::Itertools;
+        use std::{
+            io::prelude::*,
+            process::{Command, Stdio},
+        };
+
+        let process = {
+            let mut split = shlex::split(&self.selector).unwrap();
+            let (cmd, args) = (split.remove(0), split);
+            Command::new(cmd)
+                .args(args)
+                .stdin(Stdio::piped())
+                .stdout(Stdio::piped())
+                .spawn()?
+        };
+
+        process
+            .stdin
+            .unwrap()
+            .write_all(opts.join("\n").as_bytes())?;
+
+        let mut output = String::with_capacity(24);
+        process.stdout.unwrap().read_to_string(&mut output)?;
+        let output = output.trim_end().to_owned();
+
+        Ok(output)
+    }
+}
diff --git a/src/error.rs b/src/error.rs
index 08e6cba..4d4d08c 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -8,6 +8,8 @@ pub enum Error {
     Notify(#[from] notify_rust::error::Error),
     #[error(transparent)]
     Xdg(#[from] xdg::BaseDirectoriesError),
+    #[error(transparent)]
+    Config(#[from] confy::ConfyError),
     #[error("no handler defined for this mime/extension")]
     NotFound(String),
     #[error("could not figure out the mime type .{0}")]
diff --git a/src/main.rs b/src/main.rs
index 8969c20..a60c88c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,68 +1,19 @@
-use clap::Clap;
 use error::{Error, Result};
-use notify_rust::Notification;
-use std::convert::TryFrom;
 
 mod apps;
+mod cli;
 mod common;
+mod config;
 mod error;
 
-use common::{DesktopEntry, FlexibleMime, Handler, MimeOrExtension};
-
-#[derive(Clap)]
-#[clap(global_setting = clap::AppSettings::DeriveDisplayOrder)]
-#[clap(global_setting = clap::AppSettings::DisableHelpSubcommand)]
-#[clap(version = clap::crate_version!())]
-enum Cmd {
-    /// List default apps and the associated handlers
-    List,
-
-    /// Open a path/URL with its default handler
-    Open {
-        #[clap(required = true)]
-        path: Vec<String>,
-    },
-
-    /// Set the default handler for mime/extension
-    Set {
-        mime: MimeOrExtension,
-        handler: Handler,
-    },
-
-    /// Unset the default handler for mime/extension
-    Unset { mime: MimeOrExtension },
-
-    /// Launch the handler for specified extension/mime with optional arguments
-    Launch {
-        mime: MimeOrExtension,
-        args: Vec<String>,
-    },
-
-    /// Get handler for this mime/extension
-    Get {
-        #[clap(long)]
-        json: bool,
-        mime: MimeOrExtension,
-    },
-
-    /// Add a handler for given mime/extension
-    /// Note that the first handler is the default
-    Add {
-        mime: MimeOrExtension,
-        handler: Handler,
-    },
-
-    #[clap(setting = clap::AppSettings::Hidden)]
-    Autocomplete {
-        #[clap(short)]
-        desktop_files: bool,
-        #[clap(short)]
-        mimes: bool,
-    },
-}
-
 fn main() -> Result<()> {
+    use clap::Clap;
+    use cli::Cmd;
+    use common::MimeType;
+    use std::convert::TryFrom;
+
     let mut apps = apps::MimeApps::read()?;
+    crate::config::Config::load()?;
 
     let res = || -> Result<()> {
         match Cmd::parse() {
@@ -78,14 +29,9 @@ fn main() -> Result<()> {
             Cmd::Get { mime, json } => {
                 apps.show_handler(&mime.0, json)?;
             }
-            Cmd::Open { path } => {
-                std::process::Command::new("notify-send")
-                    .arg(&format!("{:?}", path))
-                    .spawn()?;
-                apps.get_handler(
-                    &FlexibleMime::try_from(path.get(0).unwrap().as_str())?.0,
-                )?
-                .launch(path)?;
+            Cmd::Open { paths } => {
+                let mime = MimeType::try_from(paths[0].as_str())?.0;
+                apps.get_handler(&mime)?.launch(paths)?;
             }
             Cmd::List => {
                 apps.print()?;
@@ -110,12 +56,13 @@ fn main() -> Result<()> {
     match (res, atty::is(atty::Stream::Stdout)) {
         (Err(e), true) => eprintln!("{}", e),
         (Err(e), false) => {
-            Notification::new()
+            notify_rust::Notification::new()
                 .summary("handlr error")
                 .body(&e.to_string())
                 .show()?;
         }
         _ => {}
     };
+
     Ok(())
 }