Всем привет! Часто ли вы опечатываетесь во время работы в терминале? Уверен, что каждый хоть раз забывал sudo или вместо cd писал cs. Как-то раз увидел алиас fuck для добавления sudo к предыдущей команде. Я заинтересовался и начал копать.
Первое решение заслуживающее уважения
В своих поисках нашел утилиту thefuck. Кроме простого добавления sudo там где это нужно, она может исправить опечатку в команде, в под команде, добавить недостающие флаги и много другого.
Но для себя я нашел 2 недостатка: программа написана на Python из-за чего она может быть немного медленной и программа давно не поддерживается, соответственно не работает на новых версиях языка.
Быстрая альтернатива
Мы же тут программисты, подумал я, и решил написать альтернативу на Rust под названием theshit. Честно говоря, это был мой первый опыт с Rust от этого было еще интереснее. Автор thefuck применил очень интересный подход по передаче последней команды в программу, который я любязно позаимствовал. Мы не вызываем нашу программу напрямую, а создаем специальный алиас(функцию) для shell’а.
Пример алиаса theshit для zsh:
{name}() { # {name} - имя алиаса export SH_SHELL=zsh; SH_PREV_CMD=\"$(fc -ln -1)\"; export SH_PREV_CMD; SH_SHELL_ALIASES=$(alias); export SH_SHELL_ALIASES; SH_CMD=$( {} fix $@ # {} - путь к программе ) && eval \"$SH_CMD\"; unset SH_PREV_CMD; unset SH_SHELL; unset SH_SHELL_ALIASES; }
Как видите мы всю нужную информацию передаем через переменные окружения и встроенные в оболочку команды. А как мы исправляем команды? Собственно также как и в thefuck, у нас есть некие «правила», которые состоят из 2 функций — проверка и исправления.
Пример правила для исправление под команды cargo:
pub fn is_match(command: &Command) -> bool { command.output().stderr().contains("no such command") && command .output() .stderr() .contains("a command with a similar name exists:") && command.parts()[0] == "cargo" } pub fn fix(command: &Command) -> String { let broken = &command.parts()[1]; let fix = Regex::new(r"a command with a similar name exists: `([^`]*)`") .unwrap() .captures(command.output().stderr()) .and_then(|caps| caps.get(1)) .map(|m| m.as_str()) .unwrap(); misc::replace_argument(command.command(), broken, fix) }
Когда мы пишем команду с ошибкой, cargo сам говорит правильный аналог. Например:
❯ cargo builrt error: no such command: `builrt` help: a command with a similar name exists: `build` help: view all installed commands with `cargo --list` help: find a package to install `builrt` with `cargo search cargo-builrt`
Мы в свою очередь просто проверяем есть ли подсказка и вытаскиваем ее.
Заключение
Я вам рассказал о 2 утилитах для коррекции ошибок и принцип их работы. Надеюсь вам понравилось и вы будете быстрее работать в терминале. А на последок хочу попросить помощи в разработке и тестировании theshit — открывайте issue, присылайте пулл реквесты, а главное — не бойтесь экспериментировать.
ссылка на оригинал статьи https://habr.com/ru/articles/936056/
Добавить комментарий