Как стать автором
Поиск
Написать публикацию
Обновить

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

Уровень сложностиПростой
Время на прочтение2 мин
Количество просмотров1.1K

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

Теги:
Хабы:
+5
Комментарии4

Публикации

Ближайшие события