LINUX.ORG.RU

Запускатор программ/открыватор файлов на bash/zsh

 , ,


0

3

Хочу себе запускатор, который работает по такому принципу - по кейбинду открывается окошко терминала с заданной мною геометрией, там я могу указать имя проги или имя файла для выполнения/открытия, жму ентер, окошко закрывается, программа выполняется.

Пока сделал так:

cat .zshrc

xo () {
xdg-open $1 &
disown
exit
}

xr () {
$1 &
disown
exit
}
По специальному сочетанию клавиш открывается терминал 100x5 столбцов, по команде

xo ФАЙЛ

Файл открывается через xdg-open, окошко терминала уходит

По команде

xr команда

Выполняется команда, окошко терминала уходит.

Вроде, всё неплохо, но некоторые вещи далеки от идеала:

1.) Если вызываю xo (ожидается имя файла), то автодополнение zsh работает, как надо - предлагает имя файла. При этом, если я вызываю xr, мне надо, чтобы автодополнение предлагало пути из $PATH (как если бы я не вызывал xr, а просто набрал первую букву имени проги и жал Tab), однако, оно предлагает по-прежнему автодополнять пути (что ожидаемо, ведь оно считает, что xr - команда, а её аргумент - файл). Как бы мне сделать так, чтобы автодополнение после xr предлагало команды, а не файлы?

2.) Можно ли сделать так, чтобы по-умолчанию любая вводимая команда выполнялась так, как если бы она была аргументом функции xr? То есть, я себе вижу это так: я ввожу какую-то команду, как если бы речь шла об обычном zsh/bash без каких-либо функций (автодополнение работает, как обычно), жму enter - она выполняется с отвязкой от shell, shell закрывается. Либо же я могу ввести xo ФАЙЛ и он откроется так, как полагается с учётом той функции xo.

Буду очень благодарен за все советы.

★★

Последнее исправление: Valdor (всего исправлений: 1)

Не нужно складывать все яйца в одну корзину, для запуска команд лучше всего dmenu_run, для файлов - rofi или gmrun, а терминал это очень большой оверхед для таких пустяков.

Bfgeshka ★★★★★
()
Ответ на: комментарий от Bfgeshka

Дменю плохо умеет автодополнение путей файлов для команд. На мой взгляд, терминал идеален для таких задач, осталось правильно настроить

Valdor ★★
() автор топика

Как бы мне сделать так, чтобы автодополнение после xr предлагало команды, а не файлы?

% compdef _command_names xr

salsa
()
Ответ на: комментарий от Bfgeshka

собрал из гита, такого дополнения не вижу, коммиты посмотрел и пуллреквесты тоже, вроде молчат, для этого нужна какая-то особая настройка или должно работать на дефолте?

slon
()
Ответ на: комментарий от slon

Тогда извиняюсь - думал, что там дополнение по табу.

Bfgeshka ★★★★★
()

Предлагаю

function xdg-open()
{
    emulate -L zsh
    for arg in $@ ; do
        command xdg-open $arg
    endfor
}
function _-accept-line()
{
    emulate -L zsh
    FILE="${(z)BUFFER[1]}"
    whence $FILE &>/dev/null || BUFFER="xdg-open $BUFFER"
    zle .accept-line
}
zle -N accept-line _-accept-line
(стащено отсюда: http://stackoverflow.com/a/13094262/2815355), убрать оба префикса и тупо настроить автодополнение zsh на файлы. И в твоём окне запускать zsh с профилем, где эти костыли включены. В основной профиль можно не включать, поскольку оно ломает некоторые вещи.

x3al ★★★★★
()
Ответ на: комментарий от Valdor

Да, в том числе. Введённое — в $BUFFER, можешь пользовать как аргумент для xr.

x3al ★★★★★
()

Можно объединить эти функции. Т.е. создать ещё одну, которая бы считывала ввод с клавиатуры, а потом определяла, что нужно запустить: xo или xr. Тогда можно запускать эту функцию при старте шелла и не вводить xo/xr.

sudopacman ★★★★★
()
Ответ на: комментарий от sudopacman

Во-первых, тогда, если я правильно понимаю, отвалится автодополнение.

Во-вторых, в некоторых ситуациях будет неоднозначность: редактировать скрипт или исполнять?

Valdor ★★
() автор топика
Ответ на: комментарий от Valdor

Думаю, можно как-то автодополнение прикрутить. А с исполнением можно сделать так: если скрипта нет в $PATH, функция будет спрашивать запустить или редактировать в случае у скрипта есть права на исполнение, а если их нет, будет спрашивать добавить ли их или редактировать в текстовом редакторе. Если скрипт есть в $PATH и ты хочешь его отредактировать, то тогда уже можно написать xo. Будет, конечно, сложновато, но зато результат крутой.

sudopacman ★★★★★
()
Ответ на: комментарий от sudopacman

Городить собственное автодополнение внутри функции, которая считывает аргумент из stdin? Мсье знает толк. А вот совместить функционал «открыть или выполнить» в одной функции и вызывать её - это хорошая затея.

Valdor ★★
() автор топика
Ответ на: комментарий от salsa

Кстати, тут заметил кое-что.

xr, как и полагается, предлагает теперь команды. А можно сделать так, чтобы для следующей команды (xr geany, например) работало автодополнение, как обычно?

Valdor ★★
() автор топика
Ответ на: комментарий от sudopacman

Это уже не проблема. Мне просто на секунду показалось, что ты предлагаешь запилить целую отдельную скриптовину, которая всё читает из stdin и может запускаться без шелла, собственно.

Valdor ★★
() автор топика
Ответ на: комментарий от Valdor

Я изначально предлагал лишь одну функцию сделать. Кстати, как доделаешь всё, запили скриншот в галерею. Очень интересно будет посмотреть на результат столь многочисленных топиков.

sudopacman ★★★★★
()
Ответ на: комментарий от sudopacman

Да я нихрена не умею толком. Но если вдруг получится что-то, чем я смогу пользоваться - поделюсь.

Valdor ★★
() автор топика
Ответ на: комментарий от sudopacman
#!/bin/bash
if [ -e "$1" ]
then
	echo "Файл существует"
	if [ -x "$1" ]
	then
		echo "Файл исполняемый"
		if [[ "$(dirname $1)" = "." ]]
		then
			echo "Файл в текущем каталоге"
			./$* &
			disown
		else
			$* &
			disown
		fi
	else
		xdg-open "$1" &
		disown
	fi
else
	$* &
	disown
fi

Проверил на:

Неисполняемый файл по относительному/абсолютному пути, исполняемый файл по относительному/абсолютному c опциями/без.

Вроде, пашет.

Valdor ★★
() автор топика
Ответ на: комментарий от salsa

Принято, спасибо. Завтра попробую.

Valdor ★★
() автор топика
Ответ на: комментарий от Valdor

Чёт немного мне принцип непонятен. Может лучше сделать проверку на не существование файла, потом проверку на то, расположен ли он в PATH, затем на права для исполнения, а потом уже xdg-open. Т.е (баш на уровне программирования не очень знаю, так что реализуешь сам):

если файл не существует, тогда echo "файл не существует" && sleep 2 && clear
иначе,
если файл есть в $PATH, то запустить файл 
иначе,
если файл имеет права на запуск, спроисть "Запустить или открыть?"
запустить или открыть
иначе,
открыть файл

sudopacman ★★★★★
()
Ответ на: комментарий от Valdor

Только хз, как автодополнение крутить. Получается, что для первого аргумента - и команды, и пути. Для второго - как для обычной команды, которая в первом аргументе.

Может, товарищ salsa и тут даст бесценный совет?

Valdor ★★
() автор топика
Ответ на: комментарий от sudopacman

Я так рассуждал - Если файл не существует, то либо пользователь указал не то, либо это - команда из PATH. Тогда мы её выполним. Если не получилось - пользователь ошибся, делать нечего.

Если же файл существует, то если он исполняемый - исполним, иначе — откроем.

Пожалуй, единственное, что надо еще обработать - случай, когда файл назван по имени, и он есть и в текущем каталоге, и в PATH.

Твое предложение рухнет на этапе проверки, есть ли файл, ведь придётся весь PATH проверять, иначе останемся вообще без его содержимого.

А вопрос «исполнить или открыть» - косметическая мелочь, запилить легко.

Valdor ★★
() автор топика
Последнее исправление: Valdor (всего исправлений: 2)
Ответ на: комментарий от Valdor

Сходу ничего путного не вышло, может завтра еще попробую. Но лучше углубиться в тему самостоятельно, ведь еще не раз допиливать будете. Навскидку, это лучше с помощью _arguments делать.

salsa
()
Ответ на: комментарий от salsa

Принято, завтра почитаю про принципы автодополнения zsh. Может, повезет

Valdor ★★
() автор топика
Ответ на: комментарий от sudopacman

Переработал. На свежий мозг мне твой вариант показался более правильным:

#!/bin/bash
if [ `compgen -c | grep -x "$1"` ]
then
	echo "Файл находится в PATH"
	$* &
	disown
elif [ -e "$1" ]
then
	echo "Файл существует по указанному пути"
	if [ -x "$1" ]
	then
		if [[ "$(dirname $1)" = "." ]]
		then
			echo "Файл находится в текущем каталоге"
			./$* &
			disown
		else
			$* &
			disown
		fi
	else
		xdg-open "$1" &
		disown
	fi
else
	echo "Такого файла нет ни по указанному пути, ни в PATH"
fi

Фишка такова. Допустим, какой-то объект есть и в PATH, и в текущем каталоге. Допустим, у меня в текущем каталоге лежит файл dd, имеющий права на исполнение. Если вызову

./script.sh dd

выполнится dd из PATH

Если же

./script.sh ./dd

выполнится местный dd.

Valdor ★★
() автор топика
Последнее исправление: Valdor (всего исправлений: 2)
Ответ на: комментарий от sudopacman

sudopacman, salsa

Итак, что-то есть. Вариант для включения в .zshrc: http://pastebin.com/pz7njM9p

Отдельный скрипт: http://pastebin.com/miUbtF25

В случае с .zshrc добавлено автодополнение (которое будет автодополнять всё именно так, как соответствует моей задумке), спасибо llua из IRC-чата #zsh на FreeNode за это.

Я использую exo-open для открытия файлов, можно спокойно заменить на xdg-open, gnome-open, kde-open, если сочтёте нужным. disown можно убрать (это отцепляет команду от терминала, чтобы можно было закрыть. Предполагается, что с помощью этой функции никто не будет запускать то, что требует интерактивного ввода на stdin).

Надо ещё подрихтовать, причесать и так далее, но, кажется, функциональная часть пашет. Если будет не лень - пообкатывайте, пожалуйста.

Valdor ★★
() автор топика
Ответ на: комментарий от sudopacman

Да нахрен не нужно, я с их помощью разбирался, почему результат оказывался не тем.

Эта вундервафля умеет открывать не только локальные файлы, но и http://, ftp:// (поскольку является обёрткой над xdg-open и прочими). Можно запилить обработку других типов команд (во-первых, через написание обработчиков протоколов для тех самых xdg-open, во-вторых, через различную реакцию на разный формат аргумента).

Valdor ★★
() автор топика
Последнее исправление: Valdor (всего исправлений: 1)
Ответ на: комментарий от sudopacman

Что ещё хочу замутить - отдельные опции, которые бы открывали набранное во внешнем терминале или принудительно обрабатывали объект, не как исполняемый (т.е. открывали).

Valdor ★★
() автор топика
Ответ на: комментарий от salsa

Слушай, а ты не в курсе, как переопределить стандартное автодополнение команд, когда еще ничего не введено? Хочу, чтобы вместо автодополнения команд (когда в пускать строку только начинает что то вводить) работало вот это новое _xo, и сделать так, чтобы перед каждой командой оно автоматом вставляллсь (метод описан выше)

Valdor ★★
() автор топика
Ответ на: комментарий от Valdor

Один вопрос: почему ты пишешь две версии — для bash и в виде функции для zsh? Можно просто положить bash- (или zsh-) скрипт в $PATH, и compdef _xo xo будет работать.

shdown
()
Ответ на: комментарий от shdown

У меня и так работает. Они одинаковые теперь. Я хочу теперь минимизировать необходимые действия для использования.

Valdor ★★
() автор топика
Ответ на: комментарий от Valdor

По дополнению не подскажу, думаю, с completer'ом что-то.

чтобы перед каждой командой оно автоматом вставляллсь

Можно через подмену виджета accept-line или с помощью хука preexec.

И предвидя твои будущие хотелки, глянь еще в сторону predict-on и https://github.com/tarruda/zsh-autosuggestions.

salsa
()
Ответ на: комментарий от Valdor

Тогда и файл автодополнения можно положить куда-нибудь в $fpath.

salsa
()
Ответ на: комментарий от shdown

О, это даже изящнее, чем то, о чем я подумал. Шикарно, спасибо огромное.

Valdor ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.