mirror of
https://github.com/denisidoro/navi
synced 2024-11-10 14:04:17 +00:00
Improve bash and zsh widgets (#486)
This commit is contained in:
parent
1f3560f7f9
commit
307f0c11b2
7 changed files with 89 additions and 172 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -308,7 +308,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "navi"
|
||||
version = "2.14.0"
|
||||
version = "2.15.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "navi"
|
||||
version = "2.14.0"
|
||||
version = "2.15.0"
|
||||
authors = ["Denis Isidoro <denis_isidoro@live.com>"]
|
||||
edition = "2018"
|
||||
description = "An interactive cheatsheet tool for the command-line"
|
||||
|
|
|
@ -75,8 +75,6 @@ Feel free to be the maintainer of **navi** for any package manager you'd like!
|
|||
|
||||
### Installing the shell widget
|
||||
|
||||
The shell widget maintains your `.history`-like file consistent and allows you to edit commands before executing them.
|
||||
|
||||
If you want to install it, add this line to your `.bashrc`-like file:
|
||||
```sh
|
||||
# bash
|
||||
|
|
|
@ -1,46 +1,35 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
_call_navi() {
|
||||
local selected
|
||||
|
||||
if [ -n "${READLINE_LINE}" ]; then
|
||||
if selected="$(printf "%s" "$(navi --print --fzf-overrides '--no-select-1' --query "${READLINE_LINE}" </dev/tty)")"; then
|
||||
READLINE_LINE="$selected"
|
||||
READLINE_POINT=${#READLINE_LINE}
|
||||
fi
|
||||
else
|
||||
if selected="$(printf "%s" "$(navi --print </dev/tty)")"; then
|
||||
READLINE_LINE="$selected"
|
||||
READLINE_POINT=${#READLINE_LINE}
|
||||
fi
|
||||
_navi_call() {
|
||||
local result="$(navi "$@" </dev/tty)"
|
||||
if [ -z "${result}" ]; then
|
||||
result="$(navi --print </dev/tty)"
|
||||
fi
|
||||
printf "%s" "$result"
|
||||
}
|
||||
|
||||
__call_navi_legacy_versions() {
|
||||
local -r result="$(navi --print)"
|
||||
local -r linecount="$(echo "$result" | wc -l)"
|
||||
_navi_widget() {
|
||||
local -r input="${READLINE_LINE}"
|
||||
local -r last_command="$(echo "${input}" | navi fn widget::last_command)"
|
||||
|
||||
if [[ "$linecount" -lt 2 ]]; then
|
||||
printf "%s" "$result"
|
||||
return 0
|
||||
fi
|
||||
|
||||
IFS=$'\n'
|
||||
local i=1;
|
||||
for line in $result; do
|
||||
if echo "$line" | grep -q '\\$'; then
|
||||
printf "${line::-1} "
|
||||
elif [[ "$i" -eq "$linecount" ]]; then
|
||||
printf "$line "
|
||||
if [ -z "${last_command}" ]; then
|
||||
local -r output="$(_navi_call --print --fzf-overrides '--no-select-1')"
|
||||
else
|
||||
printf "${line}; "
|
||||
local -r find="$last_command"
|
||||
local -r replacement="$(_navi_call --print --query "${last_command}")"
|
||||
local -r output="${input//$find/$replacement}"
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
|
||||
READLINE_LINE="$output"
|
||||
READLINE_POINT=${#READLINE_LINE}
|
||||
}
|
||||
|
||||
_navi_widget_legacy() {
|
||||
_navi_call --print
|
||||
}
|
||||
|
||||
if [ ${BASH_VERSION:0:1} -lt 4 ]; then
|
||||
bind '"\C-g": " \C-b\C-k \C-u`__call_navi_legacy_versions`\e\C-e\C-a\C-y\C-h\C-e\e \C-y\ey\C-x\C-x\C-f"'
|
||||
bind '"\C-g": " \C-b\C-k \C-u`_navi_widget_legacy`\e\C-e\C-a\C-y\C-h\C-e\e \C-y\ey\C-x\C-x\C-f"'
|
||||
else
|
||||
bind -x '"\C-g": _call_navi'
|
||||
bind -x '"\C-g": _navi_widget'
|
||||
fi
|
|
@ -1,147 +1,36 @@
|
|||
#!/usr/bin/env zsh
|
||||
|
||||
# Copy-pasted from https://gist.github.com/enisozgen/2109cc80ea9f405f80c6c383f2375e77
|
||||
|
||||
|
||||
# Change last part of the command
|
||||
# NOTE Creates sometime problem if there is same word in the input
|
||||
ChangeLastCommand()
|
||||
{
|
||||
[[ -z "${2// }" ]] && printf "%s" "$(echo "${1}${3}")" || printf "%s" "$(echo "${1/$2/ $3}")"
|
||||
_navi_call() {
|
||||
local result="$(navi "$@" </dev/tty)"
|
||||
if [ -z "${result}" ]; then
|
||||
result="$(navi --print </dev/tty)"
|
||||
fi
|
||||
printf "%s" "$result"
|
||||
}
|
||||
|
||||
SendLastCommandAfterPIPE()
|
||||
{
|
||||
# Send last command after pipe
|
||||
INPUT_STRING="${1}"
|
||||
a=("${(@s/|/)${INPUT_STRING}}") # | modifier
|
||||
printf "%s" "$(echo "${a[-1]}")"
|
||||
}
|
||||
_navi_widget() {
|
||||
local -r input="${LBUFFER}"
|
||||
local -r last_command="$(echo "${input}" | navi fn widget::last_command)"
|
||||
local find="$last_command"
|
||||
local replacement="$last_command"
|
||||
|
||||
|
||||
# Is there pipe in the input string
|
||||
IsPipeExist()
|
||||
{
|
||||
INPUT_STRING=$1
|
||||
if [[ $INPUT_STRING == *\|* ]]; then
|
||||
NAVI_PIPE="true"
|
||||
if [ -z "${last_command}" ]; then
|
||||
replacement="$(_navi_call --print --fzf-overrides '--no-select-1')"
|
||||
elif [ "${LASTWIDGET}" = "_navi_widget" ] && [ "$input" = "$previous_output" ]; then
|
||||
find="$input"
|
||||
replacement="$(_navi_call --print --query "${previous_last_command:-$last_command}")"
|
||||
else
|
||||
NAVI_PIPE="false"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
IsOnlySpace ()
|
||||
{
|
||||
if [[ -z "${1// }" ]] ; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
NaviUISearch()
|
||||
{
|
||||
NAVI_RET=$(printf "%s" "$(navi --print --fzf-overrides '--no-select-1' --query "${1}" </dev/tty)")
|
||||
printf ${NAVI_RET}
|
||||
}
|
||||
|
||||
|
||||
NaviOutputControl ()
|
||||
{
|
||||
if ! [[ -z "$1" ]] ; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
|
||||
SmartNavi()
|
||||
{
|
||||
if IsOnlySpace $1 ; then
|
||||
NAVI_RET=$(printf "%s" "$(navi --print --fzf-overrides '--no-select-1' </dev/tty)")
|
||||
else
|
||||
NAVI_RET=$(printf "%s" "$(navi --print --best-match --fzf-overrides '--no-select-1' --query "${1}" </dev/tty)")
|
||||
replacement="$(_navi_call --print --best-match --query "${last_command}")"
|
||||
fi
|
||||
|
||||
previous_last_command="$last_command"
|
||||
previous_output="${input//$find/$replacement}"
|
||||
|
||||
# Return warning if there is no output else return best match
|
||||
if NaviOutputControl ${NAVI_RET}; then
|
||||
printf ${NAVI_RET}
|
||||
else
|
||||
printf "Navi Returned Empty"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
_call_navi() {
|
||||
local selected
|
||||
if [ -n "$LBUFFER" ]; then
|
||||
if selected="$(printf "%s" "$(navi --print --fzf-overrides '--no-select-1' --query "${LBUFFER}" </dev/tty)")"; then
|
||||
LBUFFER="$selected"
|
||||
fi
|
||||
else
|
||||
# If there is not any word on list
|
||||
if selected="$(printf "%s" "$(navi --print </dev/tty)")"; then
|
||||
LBUFFER="$selected"
|
||||
fi
|
||||
fi
|
||||
zle kill-whole-line
|
||||
LBUFFER="${previous_output}"
|
||||
region_highlight=("P0 100 bold")
|
||||
zle redisplay
|
||||
}
|
||||
|
||||
_call_smart_navi() {
|
||||
|
||||
# set -x
|
||||
INPUT_STRING=$LBUFFER
|
||||
IsPipeExist ${INPUT_STRING}
|
||||
|
||||
|
||||
# Is there some written stuff in LBUFFER ?
|
||||
if ! [ -z "$INPUT_STRING" ] ; then
|
||||
# If last navi output same as current input
|
||||
# Use this part when you don't like navi best match
|
||||
if [ "${LASTWIDGET}" = "_call_smart_navi" ] && [ "${OUTPUT_STRING}" = "$INPUT_STRING" ];then
|
||||
LBUFFER_LAST_COMMAND=$(SendLastCommandAfterPIPE "${INPUT_STRING}")
|
||||
|
||||
# Searching with same input as before but this time we are using navi interactive UI since navi didn't return us what we want
|
||||
OUTPUT_STRING=$(NaviUISearch ${PREVIOUS_LAST})
|
||||
OUTPUT_STRING=$(ChangeLastCommand "$INPUT_STRING" "$LBUFFER_LAST_COMMAND" "$OUTPUT_STRING")
|
||||
|
||||
else
|
||||
# First search always start from here!!!
|
||||
if [ "${NAVI_PIPE}" = "false" ] ; then
|
||||
|
||||
# LBUFFER_LAST_COMMAND=$(SendLastCommandAfterPIPE "${INPUT_STRING}")
|
||||
# PREVIOUS_LAST=$LBUFFER_LAST_COMMAND
|
||||
|
||||
# Remember what was last command after pipe
|
||||
PREVIOUS_LAST=$INPUT_STRING
|
||||
OUTPUT_STRING=$(SmartNavi ${INPUT_STRING})
|
||||
|
||||
else
|
||||
LBUFFER_LAST_COMMAND=$(SendLastCommandAfterPIPE "${INPUT_STRING}")
|
||||
|
||||
# Remember what was last command after pipe
|
||||
PREVIOUS_LAST=$LBUFFER_LAST_COMMAND
|
||||
|
||||
OUTPUT_STRING=$(SmartNavi ${LBUFFER_LAST_COMMAND})
|
||||
OUTPUT_STRING=$(ChangeLastCommand "$INPUT_STRING" "$LBUFFER_LAST_COMMAND" "$OUTPUT_STRING")
|
||||
|
||||
fi
|
||||
fi
|
||||
LBUFFER="$OUTPUT_STRING"
|
||||
else
|
||||
# There is nothing use default navi command
|
||||
_call_navi
|
||||
fi
|
||||
|
||||
region_highlight=("P0 100 bold")
|
||||
zle redisplay
|
||||
}
|
||||
|
||||
|
||||
zle -N _call_smart_navi
|
||||
bindkey '^g' _call_smart_navi
|
||||
zle -N _navi_widget
|
||||
bindkey '^g' _navi_widget
|
||||
|
|
|
@ -2,11 +2,13 @@ use crate::handler;
|
|||
use crate::structures::config;
|
||||
use crate::url;
|
||||
use anyhow::Error;
|
||||
use std::io::{self, Read};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Func {
|
||||
UrlOpen,
|
||||
Welcome,
|
||||
WidgetLastCommand,
|
||||
}
|
||||
|
||||
pub fn main(func: &Func, args: Vec<String>) -> Result<(), Error> {
|
||||
|
@ -15,5 +17,43 @@ pub fn main(func: &Func, args: Vec<String>) -> Result<(), Error> {
|
|||
Func::Welcome => handler::handle_config(config::config_from_iter(
|
||||
"navi --path /tmp/navi/irrelevant".split(' ').collect(),
|
||||
)),
|
||||
Func::WidgetLastCommand => widget_last_command(),
|
||||
}
|
||||
}
|
||||
|
||||
fn widget_last_command() -> Result<(), Error> {
|
||||
let mut text = String::new();
|
||||
io::stdin().read_to_string(&mut text)?;
|
||||
|
||||
let replacements = vec![("|", "ඛ"), ("||", "ග"), ("&&", "ඝ")];
|
||||
|
||||
let parts = shellwords::split(&text).unwrap_or_else(|_| text.split('|').map(|s| s.to_string()).collect());
|
||||
|
||||
for p in parts {
|
||||
for (pattern, escaped) in replacements.clone() {
|
||||
if p.contains(pattern) && p != pattern {
|
||||
let replacement = p.replace(pattern, escaped);
|
||||
text = text.replace(&p, &replacement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut extracted = text.clone();
|
||||
for (pattern, _) in replacements.clone() {
|
||||
let mut new_parts = text.rsplit(pattern);
|
||||
if let Some(extracted_attempt) = new_parts.next() {
|
||||
if extracted_attempt.len() <= extracted.len() {
|
||||
extracted = extracted_attempt.to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (pattern, escaped) in replacements.clone() {
|
||||
text = text.replace(&escaped, &pattern);
|
||||
extracted = extracted.replace(&escaped, &pattern);
|
||||
}
|
||||
|
||||
println!("{}", extracted.trim_start());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ impl FromStr for Func {
|
|||
match s {
|
||||
"url::open" => Ok(Func::UrlOpen),
|
||||
"welcome" => Ok(Func::Welcome),
|
||||
"widget::last_command" => Ok(Func::WidgetLastCommand),
|
||||
_ => Err("no match"),
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +148,7 @@ pub enum Command {
|
|||
/// Performs ad-hoc functions provided by navi
|
||||
Fn {
|
||||
/// Function name (example: "url::open")
|
||||
#[clap(possible_values = &["url::welcome", "open"], case_insensitive = true)]
|
||||
#[clap(possible_values = &["url::welcome", "open", "widget::last_command"], case_insensitive = true)]
|
||||
func: Func,
|
||||
/// List of arguments (example: "https://google.com")
|
||||
args: Vec<String>,
|
||||
|
|
Loading…
Reference in a new issue