The Shit — Скажи опечаткам НЕТ

от автора

Всем привет! Часто ли вы опечатываетесь во время работы в терминале? Уверен, что каждый хоть раз забывал 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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *