Skip to content

Commit

Permalink
Merge pull request #37 from Shizcow/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
Shizcow authored Nov 29, 2020
2 parents 28e523c + da7fb76 commit aeadc2b
Show file tree
Hide file tree
Showing 14 changed files with 253 additions and 11 deletions.
2 changes: 1 addition & 1 deletion config.mk
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION = 5.4.0
VERSION = 5.5.0

# paths
PREFIX = /usr/local
Expand Down
2 changes: 1 addition & 1 deletion src/dmenu/drw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ impl Drw {
FcPatternAddBool(fcpattern as *mut c_void, FC_COLOR, FcFalse);

FcConfigSubstitute(ptr::null_mut(), fcpattern as *mut c_void, FcMatchPattern);
let mut result = MaybeUninit::uninit().assume_init(); // XftFontMatch isn't null safe so we need some memory
let mut result: x11::xft::FcResult = x11::xft::FcResult::NoId; // XftFontMatch isn't null safe so we need some memory (result is actually discarded)
let font_match = XftFontMatch(self.dpy, self.screen, fcpattern as *const FcPattern, &mut result);

FcCharSetDestroy(fccharset);
Expand Down
1 change: 1 addition & 0 deletions src/dmenu/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ impl Drw {
ret.pseudo_globals.lrpad = ret.fonts[0].height as i32;

ret.items = if ret.config.nostdin {
ret.format_stdin(vec![])?;
grabkeyboard(ret.dpy, ret.config.embed)?;
Some(Items::new(Vec::new()))
} else {Some(Items::new(
Expand Down
3 changes: 2 additions & 1 deletion src/dmenu/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ impl Items {
}, rangle_width)?;

if matched_partitions.len() == 0 {
drw.items.as_mut().unwrap().cached_partitions = matched_partitions;
return Ok(false); // nothing to draw
}

Expand Down Expand Up @@ -209,7 +210,7 @@ impl Items {
}
}
}

drw.items.as_mut().unwrap().cached_partitions = matched_partitions;

Ok(true)
Expand Down
4 changes: 2 additions & 2 deletions src/dmenu/plugin_entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ impl Drw {
/**
* When taking input from stdin, apply post-processing
*/
pub fn format_stdin(&self, lines: Vec<String>) -> CompResult<Vec<String>> {
pub fn format_stdin(&mut self, lines: Vec<String>) -> CompResult<Vec<String>> {
Ok(lines)
}

/**
* Every time the input is drawn, how should it be presented?
* Does it need additional processing?
*/
pub fn format_input(&self) -> CompResult<String> {
pub fn format_input(&mut self) -> CompResult<String> {
Ok(self.input.clone())
}

Expand Down
3 changes: 2 additions & 1 deletion src/plugins/calc/deps.toml
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
rink = "0.4.5"
rink-core = "0.5.1"
async-std = {version = "1.7.0", features = ["unstable"]}
26 changes: 21 additions & 5 deletions src/plugins/calc/main.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,43 @@
use overrider::*;
use rink::*;
use rink_core::{one_line, simple_context, Context};
use std::io::Write;
use std::process::{Command, Stdio};
use std::sync::Mutex;
use std::time::Duration;
use async_std::prelude::*;
use async_std::task::block_on;

use crate::drw::Drw;
use crate::item::Item;
use crate::result::*;

lazy_static::lazy_static! {
static ref CTX: Mutex<Context> = Mutex::new(simple_context().unwrap());
}

async fn timed_eval(expr: String) -> Result<String, String> {
async {
async_std::task::spawn(async {
let xpr = expr;
one_line(&mut CTX.lock().unwrap(), &xpr)
}).await
}.timeout(Duration::from_millis(250))
.await.unwrap_or(Ok("Calculation Timeout".to_string()))
}

#[override_flag(flag = calc)]
impl Drw {
pub fn gen_matches(&mut self) -> CompResult<Vec<Item>> {
let mut ctx = load().unwrap();
let eval = self.config.prompt.clone() + " " + &self.input;
if let Ok(evaluated) = one_line(&mut ctx, &eval) {
if let Ok(evaluated) = block_on(timed_eval(eval)) {
Ok(vec![Item::new(evaluated, false, self)?])
} else {
Ok(vec![])
}
}
pub fn dispose(&mut self, _output: String, recommendation: bool) -> CompResult<bool> {
let mut ctx = load().unwrap();
let eval = self.config.prompt.clone() + " " + &self.input;
let output = if let Ok(evaluated) = one_line(&mut ctx, &eval) {
let output = if let Ok(evaluated) = block_on(timed_eval(eval)) {
evaluated
} else {
return Ok(false)
Expand Down
13 changes: 13 additions & 0 deletions src/plugins/lookup/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#! /bin/sh

if [ "$depcheck" != "false" ]; then
printf "Checking for xdg-open... "
if command -v xdg-open &> /dev/null
then
echo "yes"
else
echo "no"
>&2 echo "xdg-open required for plugin 'lookup' but not available. Install xdg or run make depcheck=false to continue anyway"
exit 1
fi
fi
1 change: 1 addition & 0 deletions src/plugins/lookup/deps.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
phf = { version = "0.8.0", features = ["macros"] }
13 changes: 13 additions & 0 deletions src/plugins/lookup/engines.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Edit the following to add/remove/change search engines
// The keys are the parameters for the --engine arguement
// The values are the URLs. "%s" will be replaced with the search string.
pub static ENGINES: phf::Map<&'static str, &'static str> = phf::phf_map! {
"ddg" => "https://duckduckgo.com/%s",
"crates" => "https://crates.io/crates/%s",
"docs" => "https://docs.rs/%s",
"rust" => "https://doc.rust-lang.org/std/?search=%s",
"github" => "https://github.com/search?q=%s",
"archwiki" => "https://wiki.archlinux.org/index.php?search=%s",
"dictionary" => "https://www.merriam-webster.com/dictionary/%s",
"thesaurus" => "https://www.merriam-webster.com/thesaurus/%s",
};
97 changes: 97 additions & 0 deletions src/plugins/lookup/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
use overrider::*;
use std::process::Command;

use crate::clapflags::CLAP_FLAGS;
use crate::config::ConfigDefault;
use crate::drw::Drw;
use crate::result::*;
use itertools::Itertools;

mod engines;
use engines::ENGINES;

// Format engine as prompt
// eg "ddg" -> "[Search ddg]"
fn create_search_input(engine: &str) -> CompResult<String> {
// fail early if engine is wrong
match ENGINES.get(engine) {
Some(_) => Ok(format!("[Search {}]", engine)),
None => {
return Err(Die::Stderr(format!(
"Invalid search search engine {}. Valid options are: {}",
engine,
ENGINES.keys().map(|e| format!("\"{}\"", e)).join(", ")
)))
}
}
}

// Take the output of create_search_input as prompt
// It's not very clean but hey it works
fn do_dispose(output: &str, prompt: &str) -> CompResult<()> {
let mut engine: String = prompt.chars().skip("[Search ".len()).collect();
engine.pop();

// just unwrap since the check was performed before
let search_prompt = ENGINES.get(engine.as_str())
.unwrap().to_string().replace("%s", output);

// TODO: consider user defined open command for cross-platform awareness
Command::new("xdg-open")
.arg(search_prompt)
.spawn()
.map_err(|_| Die::Stderr("Failed to spawn child process".to_owned()))?;
Ok(())
}

// Important: engine must become before lookup. It's a bug in overrider.
#[override_flag(flag = engine, priority = 2)]
impl Drw {
pub fn dispose(&mut self, output: String, recommendation: bool) -> CompResult<bool> {
do_dispose(&output, &self.config.prompt)?;
Ok(recommendation)
}
pub fn format_stdin(&mut self, _lines: Vec<String>) -> CompResult<Vec<String>> {
self.config.prompt = create_search_input(CLAP_FLAGS.value_of("engine").unwrap())?;
Ok(vec![]) // turns into prompt
}
}

#[override_flag(flag = listEngines, priority = 2)]
impl Drw {
pub fn format_stdin(&mut self, _: Vec<String>) -> CompResult<Vec<String>> {
Err(Die::Stdout(ENGINES.keys().join("\n")))
}
}
#[override_flag(flag = listEngines, priority = 2)]
impl ConfigDefault {
pub fn nostdin() -> bool {
true // if called with --list-engines, takes no stdin (only prints)
}
}

#[override_flag(flag = engine, priority = 2)]
impl ConfigDefault {
pub fn nostdin() -> bool {
true // if called with --engine ENGINE, takes no stdin
}
}

#[override_flag(flag = lookup, priority = 1)]
impl Drw {
pub fn dispose(&mut self, output: String, recommendation: bool) -> CompResult<bool> {
do_dispose(&output, &self.config.prompt)?;
Ok(recommendation)
}
pub fn format_stdin(&mut self, lines: Vec<String>) -> CompResult<Vec<String>> {
self.config.prompt = create_search_input(&lines[0])?;
Ok(vec![]) // turns into prompt
}
}

#[override_flag(flag = lookup, priority = 1)]
impl ConfigDefault {
pub fn nostdin() -> bool {
false // if called without --engine, takes stdin
}
}
33 changes: 33 additions & 0 deletions src/plugins/lookup/plugin.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
about: |
Open a search query in the browser. Pass --lookup to enable.
Use --engine to specify a search engine or pipe through stdin.
See src/plugins/lookup/engines.rs for custom engines at build time.
entry: main.rs
cargo_dependencies: deps.toml
build: "sh build.sh"

args:
- lookup:
help: Enter lookup mode
long_help: >
The input in the prompt will be used as the search term in the selected
engine. XDG-OPEN will be used for opening generated links.
short: L
long: lookup
conflicts_with: prompt
- engine:
help: Engine to use
long_help: >
Engine to lookup with. Run `dmenu --lookup --list-engines`
to show available engines. More engines can be added at
src/plugins/lookup/engines.rs during build time.
long: engine
takes_value: true
requires: lookup
- listEngines: # overrider doesn't like underscores
help: List available engines
long_help: >
List available engines for lookup. Prints a newline seperated list to stdout.
long: list-engines
requires: lookup
conflicts_with: engine
52 changes: 52 additions & 0 deletions src/plugins/maxlength/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use overrider::*;

use crate::config::ConfigDefault;
use crate::drw::Drw;
use crate::item::Item;
use crate::result::*;
use crate::clapflags::CLAP_FLAGS;

use unicode_segmentation::UnicodeSegmentation;

#[override_flag(flag = maxlength)]
impl Drw {
pub fn postprocess_matches(&mut self, current_matches: Vec<Item>) -> CompResult<Vec<Item>> {
let max_length_str_option = CLAP_FLAGS.value_of( "maxlength" );

match max_length_str_option
{
None => {
Err(Die::Stderr("Please specificy max length".to_owned()))
},
Some( max_length_str ) =>
{
let max_length_result = max_length_str.parse::<usize>();
match max_length_result
{
Err( _ ) => Err(Die::Stderr("Please specificy a positive integer for max length".to_owned())),
Ok( 0 ) => Ok( current_matches ),
Ok( max_length ) => {
// >= in place of = in case someoen pastes stuff in
// when there is a paste functionality.
if self.input.graphemes(true).count() >= max_length
{
self.dispose( self.input.graphemes(true).take( max_length ).collect(), true )?;
Err(Die::Stdout("".to_owned()))
}
else
{
Ok(current_matches)
}
}
}
}
}
}
}

#[override_flag(flag = maxlength)]
impl ConfigDefault {
pub fn nostdin() -> bool {
true
}
}
14 changes: 14 additions & 0 deletions src/plugins/maxlength/plugin.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
about: |
Specify a maximum length of input,
usually used without menu items.
Acts as a replacement for `i3-input -l`
Pass --maxlength=<MAXLENGTH> to use
entry: main.rs

args:
- maxlength:
help: Limit maximum length of input
long: maxlength
takes_value: true
value_name: MAXLENGTH
# short:

0 comments on commit aeadc2b

Please sign in to comment.