RSS
# Автоматический тайлинг в Sway
difrex.blog
Difrex(tavern,23) — All
2019-04-07 15:08:45


Я давно использую i3wm в работе, а после выхода версии 1.0 Sway я перешел на него с i3. Sway - это пракатически полностью совместимый с i3 композитор Wayland. По-этому перейти на него оказалось очень просто. Мои конфиги Sway можно посмотреть на Github.

Почему-то я долгое время думал, что мне в i3/sway не хватает полностью ручного тайлинга, я пробовал различные оконные менеджеры с ручным тайлингом, такие как, `bspwm`, `herbstlutfwm` и другие, но они не заходили. Потом я решил попробовать AwesomeWM, все-таки это по сути фреймворк и на Lua можно написать все, что угодно. В нем мне очень понравилась стандартная возможность автоматического тайлинга. Вот, что мне переодически нужно, подумал я. Но во всех WM, что я пробовал не было нормальной поддержки скретчпадов - это такие плавающие окна, которые большую часть времени скрыты, и показать их можно, например по комбинации клавишь. Что же мне на самом деле хотелось от WM - скретчпады, полуручной и автоматический тайлинг, возможность менять поведение скриптами на любом языке. По всем параметрам подходил Sway за исключением автоматического тайлинга. Было решено добавить его самостоятельно.

После небольшого иследования этого вопроса оказалось, что у sway есть IPC с возможностью подписки на определенные события. Проблема возникла в том, что существующие биндинги к i3 ipc не подходили, т.к. формат дерева в JSON у Sway отличается, а так же добавляются новые возможности, типа, получения устройств ввода, чего не было в i3.

Так я решил написать(и написал) биндинг к Sway IPC на Go. И уже поверх этого начал писать демона, который реализует автоматический тайлинг.

На данный момент я реализовал `spiral` layout, который работает, так как я хочу и полностью меня устраивает. Так же на начальном этапе реализован `left` layout. Демонстрацию этих режимов можно посмотреть в видео ниже.

## Как этим воспользоваться?

Для начала нужно скомпилировать swaymgr. Из зависимостей только Go - поставь его из репозиториев твоего дистрибутива.


git clone https://github.com/Difrex/gosway
cd gosway/swaymgr
go get -t -v ./...
go build -o ~/.local/bin/swaymgr


Теперь можно добавить swaymgr в конфигурацию sway. Добавь следующие строчки в `~/.config/sway/config`


exec_always ~/.local/bin/swaymgr
bindsym $mod+Alt+m exec ~/.local/bin/swaymgr -s 'set manual'
bindsym $mod+Alt+l exec ~/.local/bin/swaymgr -s 'set left'
bindsym $mod+Alt+s exec ~/.local/bin/swaymgr -s 'set spiral'


Комбинации клавишь меняй по своему вкусу.

Swaymgr запоминает свою расскладку для каждого рабочего стола, а состояние хранит в `~/.autotiling.bolt`. В репозитории ты так же найдешь скрипт, который можно использовать, например, с `i3blocks`.

## Про внутреннее устройство

Если вдруг тебе захочется помочь в разработке, то вот небольшой гайд по тому, как правильно это сделать.

Swaymgr - это отлельное приложение, которое использует `gosway/ipc`.

Для того, чтобы взаимодействовать со Sway через unix-socket необходимо два подключения:

1. Соединение для передачи различных комманд
2. Соединение на которое будут приниматься события от оконного менеджера

Так же для хранения настроек рабочих столов используется встроенная, минималистичная база данных Bolt. Функция `newManager() (*manager, error)` создает все необходимые подключения и вызывает функцию инициализации интерфейсов `Layout`. Возвращаемая структура имеет такой вид:


type manager struct {
commandConn *ipc.SwayConnection
listenerConn *ipc.SwayConnection
store *store
layouts map[string]Layout
}


Главный интерфейс, с помощью которого реализуются все режимы - Layout, выглядит он так: Файл `swaymgr/layouts.go`


type Layout interface {
// PlaceWindow must receive an *ipc.Event
// and do the container manipulation
PlaceWindow(*ipc.Event) error
// Manage must store WorkspaceConfig in the database with
// the workspace name, layout name and with the Managed: true
Manage() error
}


У этого интерфейса есть всего два метода:

* `Manage() error` - вызывается тогда, когда текущий рабочий стол переключается в какой-либо режим
* `PlaceWindow(*ipc.Event) error` - вызывается тогда, когда создается новый контейнер на рабочем столе, который является управляемым.

### Как работает spiral layout

Я рассмотрю управлене окнами на примере реализации режима spiral.

Структура этого режима состоит всего из двух полей:

* `Conn *ipc.SwayConnection` - Коммандное подключение к unix-сокету Sway
* `store *store` - Открытое соединение к базе данных, в котой хранятся текущие настройки рабочих столов

При наступлении события создания нового окна, и если текущий рабочий стол управляется, данное событие передается в метод `PlaceWindow(event *ipc.Event)`. Для начала необходимо найти текущее окно на котором находится фокус:


nodes, err := s.Conn.GetFocusedWorkspaceWindows()
if err != nil {
return err
}
var result ipc.Node
for _, node := range nodes {
if node.Focused {
result = node
break
}
}


Далее вся логика позиционированния окон помещается в 7 строчек:


if result.WindowRect.Width > result.WindowRect.Height {
_, err := s.Conn.RunSwayCommand(fmt.Sprintf("[con_id=%d] split h", event.Container.ID))
return err
} else {
_, err := s.Conn.RunSwayCommand(fmt.Sprintf("[con_id=%d] split v", event.Container.ID))
return err
}


Если у окна с фокусом длина больше ширины, то новый контейнер разделяем по горизонтали, иначе по вертикали. Все. Это работает замечательно и эту логику работы менять я не буду.

## Зарезервированные режимы

Я заранее зарезервировал некоторые режимы которые очень хочется реализовать. Вот они:

* `type FiberLayout struct{}` - режим подсмотренный в AwesomeWM. Окна размещаются симметрично друг под другом и вдоль
* `type TopLayout struct{}` - самое большое окно размещается вверху экрана, остальные внизу разделяясь по горизонтали
* `type BottomLayout struct{}` - тоже самое, что и для TopLayout, но главное окно находится внизу
* `type RightLayout struct{}` - тоже самое, что и LeftLayout, но главное окно размещается справа

Проект на Github. Учитывай, что это пока самая ранняя реализация и тут могут быть баги в больших колличествах, правда ничего критичного я пока не находил - пользоваться можно. Буду очень рад баг-репортам и фич-реквестам, а так же особенно пулл-реквестам. Лицензия проекта: Apache.

Ссылка: https://difrex.lessmore.pw/post/sway-autotiling/

# Ограничиваем в правах Firefox с помощью apparmor
difrex.blog
Difrex(tavern,23) — All
2018-11-27 09:45:36


> AppArmor — программный инструмент упреждающей защиты, основанный на политиках безопасности, которые определяют, к каким системным ресурсам и с какими привилегиями может получить доступ то или иное приложение. В AppArmor включён набор стандартных профилей, а также инструменты статического анализа и инструменты, основанные на обучении, позволяющие ускорить и упростить построение новых профилей.

© Wikipedia.org

Самое опасное приложение на десктопе, как я считаю, - это браузер. На меня напал очередной приступ паранои и я написал профиль apparmor для Firefox.

## tl;dr

Ставим утилиты:


pacman -S apparmor audit


Apparmor входит в ядро, так что нужно только его включить передав соответствующие параметры в cmdline Linux. Правим /etc/default/grub:


GRUB_CMDLINE_LINUX="apparmor=1 security=apparmor audit=1"


Включаем сервисы:


systemctl enable apparmor
systemctl enable auditd


Разрешаем себе читать audit.log


groupadd -r audit
gpasswd -a USERNAME audit


В /etc/audit/auditd.conf прописываем только что созданную группу: `log_group = audit`

Перезагружаемся

Проверяем статус apparmor:


apparmor_status
apparmor module is loaded.
62 profiles are loaded.
49 profiles are in enforce mode.
...
SKIP
...


Пишем профиль /etc/apparmor.d/usr.bin.firefox


#include <tunables/global>

/usr/bin/firefox {
#include <abstractions/base>
#include <abstractions/bash>

# Даем доступ к видео, памяти и tty
/dev/dri/** wr,
/dev/dri/ r,
/dev/shm/ r,
/dev/tty* rw,
/dev/shm/* rw,

# Даем доступ к конфигам, а так же сети и SSL
/etc/fonts/** r,
/etc/drirc r,
/etc/mime.types r,
/etc/pulse/client.conf r,
/etc/nsswitch.conf r,
/etc/ca-certificates/** r,
/etc/resolv.conf r,
/etc/host.conf r,
/etc/ssl/openssl.cnf r,
/etc/hosts r,
/etc/gai.conf r,
/etc/machine-id r,

# Разрешаем исполнение самого себя
# /usr/bin/bash ix,
/usr/bin/firefox rix,
/usr/bin/chrome-gnome-shell rix,
# Разрешаем грепать
/bin/grep ixr,

# Доступ к библиотека на чтение/подключение
/usr/lib/* rm,
/usr/lib/dri/* rm,
/usr/lib/python3.7/** rm,
/usr/lib/firefox/** rixm,

# Доступ к системным FS
/sys/devices/system/cpu/present r,
/proc/** r,
/sys/devices/** r,

/usr/share/hunspell/ r,
/usr/share/fonts/** rwkl,
/usr/share/sounds/** r,
# тут 1000 нужно заменить на id своего юзера
/run/user/1000/** r,

# Разрешаем писать во временную директорию
/tmp/** rwk,

# Даем права на чтение/запись/лок/линкинг
/run/user/1000/** rwkl,
# Разрешаем писать в сокет dbus
/var/run/dbus/system_bus_socket w,

# Шрифты/значки и.т.д
/var/cache/fontconfig/** r,
/var/lib/flatpak/exports/** r,
/usr/share/fonts/ r,
/usr/share/icons/** r,
/usr/share/glib-2.0/** r,
/usr/lib/firefox/** rwkix,
/usr/share/ca-certificates/** r,
/usr/lib/gtk-3.0/** rmk,
/usr/share/applications/kde4/ r,
/usr/share/pixmaps/ r,
/usr/share/icons/ r,
/usr/share/libthai/thbrk.tri r,
/usr/local/share/applications/ r,
/usr/local/share/applications/* r,
/usr/local/share/mime/mime.cache r,
/usr/share/applications/ r,
/usr/share/applications/* r,
/usr/share/gdm/applications/ r,
/usr/share/gdm/applications/* r,
/usr/share/locale-langpack/** r,
/usr/share/gtk-3.0/** r,
/usr/share/mime/** r,
/usr/share/myspell/** r,
/usr/share/themes/** r,

# Назначаем Firefox влядельцем ~/.mozilla и даем ему там все права
# кроме исполнения и подключения библиотек
owner @{HOME}/.mozilla/** rwkl,
@{HOME}/.cache/fontconfig/** r,
@{HOME}/.cache/mozilla/** rwk,
@{HOME}/.cache/thumbnails/** r,
@{HOME}/.config/dconf/* rkw,
@{HOME}/.fonts/ r,
@{HOME}/.local/share/icons/** r,
@{HOME}/.cache/mesa_shader_cache/index rwk,
@{HOME}/.local/lib/python3.7/** rm,
@{HOME}/.config/fcitx/dbus/* r,
@{HOME}/.local/share/recently-used.xbel rk,

# Определяем каталоги в домашней директории куда можно ходить
# Firefox и с какими правами.
# В моем случае браузер не может даже получить список
# каталогов, но может читать в разрешенных местах и писать в ~/Загрузки
@{HOME}/Изображения/ r,
@{HOME}/Документы/ r,
@{HOME}/Загрузки/ r,
@{HOME}/Видео/ r,
@{HOME}/Музыка/ r,
@{HOME}/soft/ r,
@{HOME}/Изображения/** r,
@{HOME}/Документы/** r,
@{HOME}/Музыка/** r,
@{HOME}/Загрузки/** rwk,
@{HOME}/Видео/** r,
@{HOME}/soft/** r,

# Кэши и локальные конфиги
@{HOME}/.local/share/fonts/ r,
@{HOME}/.fonts/** r,
@{HOME}/.ICEauthority r,
@{HOME}/.Xauthority r,
@{HOME}/.adobe/**/ r,
@{HOME}/.config/* r,
@{HOME}/.cache/* wrk,
@{HOME}/.config/gtk-2.0/* r,
@{HOME}/.config/gtk-3.0/* r,
@{HOME}/.fonts.conf r,
@{HOME}/.icons/ r,
@{HOME}/.local/share/applications/ r,
@{HOME}/.local/share/applications/* r,
@{HOME}/.local/share/fonts/** r,
@{HOME}/.local/share/icons/ r,
@{HOME}/.local/share/mime/mime.cache r,
@{HOME}/.pulse-cookie krw,
@{HOME}/.config/pulse/** krw,
}


PULL THE LEVER


aa-enforce /etc/apparmor.d/usr.bin.firefox
Назначение /etc/apparmor.d/usr.bin.firefox принудительного режима.


Теперь можно запустить браузер и проверить его работоспособность. Наблюдаем через `tail -f /var/log/audit/audit.log | grep DENIED` что было запрещенно Firefox.

Для меня, например, это:


type=AVC msg=audit(1543307263.804:81037): apparmor="DENIED" operation="open" profile="/usr/bin/firefox" name="/etc/passwd" pid=31159 comm="firefox" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
type=AVC msg=audit(1543307263.884:81039): apparmor="DENIED" operation="exec" profile="/usr/bin/firefox" name="/usr/bin/lsb_release" pid=31177 comm="firefox" requested_mask="x" denied_mask="x" fsuid=1000 ouid=0
type=AVC msg=audit(1543307263.991:81040): apparmor="DENIED" operation="open" profile="/usr/bin/firefox" name="/dev/" pid=31156 comm="firefox" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
type=AVC msg=audit(1543307266.698:81043): apparmor="DENIED" operation="open" profile="/usr/bin/firefox" name="/usr/bin/" pid=31493 comm="chrome-gnome-sh" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
type=AVC msg=audit(1543307266.944:81044): apparmor="DENIED" operation="exec" profile="/usr/bin/firefox" name="/usr/bin/ldconfig" pid=31533 comm="chrome-gnome-sh" requested_mask="x" denied_mask="x" fsuid=1000 ouid=0
type=AVC msg=audit(1543307266.968:81045): apparmor="DENIED" operation="exec" profile="/usr/bin/firefox" name="/usr/bin/gcc" pid=31534 comm="chrome-gnome-sh" requested_mask="x" denied_mask="x" fsuid=1000 ouid=0


Зачем браузеру запускать компилятор я категорически не понимаю.

Смотрим еще раз в `apparmor_status`, в конце должно быть что-то подобное:


...
9 processes are in enforce mode.
/usr/lib/firefox/firefox (587) /usr/bin/firefox
/usr/lib/firefox/firefox (3857) /usr/bin/firefox
/usr/lib/firefox/firefox (31156) /usr/bin/firefox
/usr/lib/firefox/firefox (31212) /usr/bin/firefox
/usr/lib/firefox/firefox (31298) /usr/bin/firefox
/usr/bin/python3.7 (31491) /usr/bin/firefox
/usr/lib/firefox/firefox (31516) /usr/bin/firefox
/usr/bin/ntpd (1462) /usr/{bin,sbin}/{,open}ntpd
/usr/bin/dnsmasq (1510) dnsmasq


Все довольно просто в отличии от того же SELinux. А еще у apparmor есть очень хорошая документация с quick guide.

Ссылка: https://difrex.lessmore.pw/post/apparmor-firefox/

# Читаем почту в GNU Emacs
difrex.blog
Difrex(tavern,23) — All
2018-08-21 14:00:20


И так по обсуждению из вот этого вот треда(стартовый пост) у меня получилось настроить Gnus для работы с пятью почтовыми аккаунтами и отказаться от Evolution.

На самом деле связка получилась такая: fetchmail забирает письма, раз в 5 минут и запускает procmail для фильтрации сообщений, procmail сохраняет сообщения в $MAILDIR, дальше уже Gnus читает почту и показывает ее. Чтобы иметь нормальные уведомления я использую индексер почты mu, i3blocks запускает раз в 30 секунд скрипт проверки на новые письма и отправляет уведовления через libnotify, ну и иконку на панели рисует.

Вот так примерно это выглядит в ASCII-арте:


+-----------+ +------------+ +------------+ +------------+
| fetchmail | |procmail | |Maildir | |Gnus |
| +-----+filters +----+ +----+ |
+----+------+ +------------+ +-----+------+ +------+-----+
| | |
| | |
| | |
| +--------------+ +-----+------+ +-----+-----+
| |i3blocks | |mu indexer | |BBDB |
| |libnotify +----------+ | |contacts |
| +--------------+ +-----+------+ +-----------+
| |
| |
| +-----+------+
+------------------------------+systemd user|
|and timers |
+------------+


> Такие cхемки, кстати, очень удобно рисовать в artist-mode

Я настраивал все на Arch Linux, но на самом деле это все заработает в любом GNU Linux.

## Ставим пакеты

Ставим пакеты:


sudo pacman -S mu fetchmail procmail


Ставим BBDB в Emacs


M-x package-install RET bbdb RET
M-x package-install RET all-the-icons-gnus RET


BBDB нам нужен для автодополнения контактов в поле To. Да и вообще это хорошая быстрая база контактов для Emacs. А вот пакет all-the-icons-gnus рисует красивые иконки :).

## Правим конфиги

### fetchmail

Для начала нам необходимо настроить fetchmail, который будет забирать почту по IMAP/POP.

Редактируем ~/.fetchmailrc:


set daemon 300 # fetch mail every 5 minutes
set logfile ~/Mail/fetchmail.log # Logfile

poll imap.gmail.com with proto IMAP
user 'YOU_USER' there with password 'YOU_PASSWORD'
options ssl keep
mda 'procmail -d %T'


Подобным образом определяем все свои аккаунты.

Чтобы не использовать пароли в открытом виде можно наложить патч на fetchmail.

### procmail

Для фильтрации почты и расскидывания ее по каталогам будем использовать procmail - у него отличная гибкая система фильтров на регекспах.

Редактируем ~/.procmailrc:


MAILDIR=$HOME/Mail # You'd better make sure it exists

DEFAULT=$MAILDIR/mbox/
LOGFILE=$MAILDIR/log
LOCKFILE=$HOME/.lockmail

:0 # socials
* ^From.*@.*(twitter|vk\.com|facebook|golos\.io)
social/

:0 # JIRA
* .*Subject.*(\[JIRA\]|\[WGJIRA\]).*
jira/

:0 # Gitlab
* ^From.*gitlab@gitlab.*
Gitlab/


Свои фильтры пишем дальше аналогично - тут все просто. Да, и убедитесь, что каталог `$MAILDIR` существует.

### msmtp

msmtp эта штука, которая позволяет отправлять письма через нужный сервер smtp. Определяет аккаунт она по полю From.

Редактируем ~/.msmtprc:


defaults
auth on
tls on
logfile ~/.msmtp.log
tls_certcheck on
tls_trust_file /etc/ssl/cert.pem

account difrex
host smtp.googlemail.com
port 587
from my.mail@gmail.com
user USERNAME
password PASSWORD


Аналогично для остальных аккаунтов.

### Systemd

Теперь необходимо написать нужные юниты и таймеры. Юнит для fetchmail будет выглядеть так:

~/.config/systemd/system/fetchmail.service


[Unit]
Description=Fetchmail
After=network-online.target

[Service]
Type=forking
ExecStart=/usr/bin/fetchmail

[Install]
WantedBy=default.target


Включаем и запускаем его:


systemctl --user enable fetchmail.service
systemctl --user start fetchmail.service


Теперь fetchmail будет стартовать после успешного логина в систему.

Настроим индексацию почты в mu:

~/.config/systemd/user/mu.timer


[Unit]
Description=mu mail indexer timer
Documentation=man:mu(1)

[Timer]
OnCalendar=*:0/5

[Install]
WantedBy=timers.target



И сервис

~/.config/systemd/system/mu.service


[Unit]
Description=mu email indexer
After=fetchmail.service

[Service]
Type=oneshot
ExecStart=/usr/bin/mu index
Environment=MAILDIR=/home/difrex/Mail # тут нужно указать свой MAILDIR


Включаем и стартуем


systemctl --user enable mu.timer
systemctl --user start my.timer


### i3blocks

Настроим вывод значка с колличеством непрочтенных писем в i3bar и отправку уведомлений. Для этого напишем простой скрипт на bash.

~/.config/i3/mail.sh


#!/bin/bash

MAILDIR=/home/difrex/Mail; export MAILDIR # тут нужно указать свой MAILDIR
COUNT="$(/usr/bin/mu find date:15m..now and flag:unread 2>/dev/null | wc -l)"

# Write notify lock
write_notify_lock() {
mkdir -p ~/.cache
echo $COUNT > ~/.cache/.mail_notify_lock
}

# Cleanup lock
clean_notify_lock() {
rm -f ~/.cache/.mail_notify_lock
}

if [[ $COUNT -gt 0 ]]; then
if [[ ! -f ~/.cache/.mail_notify_lock ]] || [[ $COUNT -gt $(/usr/bin/cat ~/.cache/.mail_notify_lock) ]]; then
write_notify_lock
/usr/bin/notify-send 'New mail' "$(/usr/bin/mu find date:15m..now and flag:unread 2>/dev/null | tail -1)"
fi
else
if [[ -f ~/.cache/.mail_notify_lock ]]; then
clean_notify_lock
fi
fi

echo $COUNT


> Не забываем сделать скрипт исполняемым

И в конфиг i3blocks.conf нужно добать секцию с нашим скриптом:


[mail]
label=
interval=30
command=~/.config/i3/mail.sh


Выглядит иконка в баре вот так:

А уведомление в dunst так:

## Gnus

Переходим к самому интересному, а именно к настройке Gnus.

Редактируем файл ~/.gnus.el.


;;; .gnus.el --- GNUs configuration
;;; Commentary:
;;; Code:

(require 'all-the-icons-gnus) ;; Наводим красоту
(all-the-icons-gnus-setup)

(setq user-mail-address "my_email@example.com") ;; Будет по-умолчанию в поле From
(setq user-full-name "Denis Zheleztsov") ;; Устанавливаем, как нас зовут

;; Показываем, что нужно смотреть в MAILDIR
(setq gnus-select-method
'(nnmaildir "mail" (directory "~/Mail"))
mail-sources '((maildir :path "~/Mail" :subdirs ("cur" "new")))
mail-source-delete-incoming nil)

;; arbitrary name after "nnmaildir+"
(setq gnus-message-archive-group "nnmaildir+mail:outbox")
(setq message-sendmail-envelope-from 'header)
(setq mail-envelope-from 'header)
(setq message-send-mail-function 'message-send-mail-with-sendmail)

;; Устанавливаем в качестве программы для отправки писем msmtp
(setq sendmail-program "/usr/bin/msmtp")
(setq message-sendmail-envelope-from 'header)

;; Сортируем письма по дате
(setq gnus-thread-sort-functions '(gnus-thread-sort-by-most-recent-date))

;; Добавляем автодополнение по TAB для поля To
(add-hook 'message-mode-hook
(function (lambda()
(local-set-key (kbd "<tab>") 'bbdb-complete-mail))))

;; Если адресса получателя нет в базе BBDB - добавляем
(add-hook 'message-setup-hook 'bbdb-mail-aliases)

;; Добавляем в базу контактов адресатов из входящей почты
(bbdb-initialize 'gnus 'message)
(bbdb-mua-auto-update-init 'gnus)
(setq bbdb-mua-auto-update-p 'create)

;; Говорим демону Gnus проверять новую почту каждые пять минут
(gnus-demon-add-handler 'gnus-demon-scan-news 5 t)
(gnus-demon-init)

;;; .gnus.el ends here


Все! Нажимаем `M-x RET gnus RET` и радуемся.

Так выглядит буфер с группами и непрочитанными сообщениями:

А так список сабжей в группе(синим цветом показаны прочитанные сообщения):

> Обновлять групповой буфер можно по g, а написать новое сообщение по m. Отправить набраное сообщение через C-c C-c. Ответ на сообщение с цитатой R, без - r.

Ссылка: https://difrex.lessmore.pw/post/gnus-multi-accounts/

# Автодополнение для python с LSP в GNU Emacs
difrex.blog
Difrex(mobile)(tavern,23) — All
2018-07-30 15:40:10


The Language Server Protocol (LSP) - это открытый, основанный на JSON-RPC протокол для использования между редакторами исходного кода и серверами, которые предоставляют специфические для языка программирования функции. Цель протокола заключается в том, чтобы обеспечить поддержку автодополнения языка программирования независимо от любого редактора или среды IDE.

LSP дает реально крутые штуки, такие как:

* Показ документации для модуля под курсором

* Автодополнение по точке. На самом деле это `company-lsp`, но про это будет дальше.

* Интеграция с flycheck

И еще кучу всего на самом деле. Все возможные настройки можно будет увидеть по `M-x customize RET lsp RET`.

## Конфигурация

Для начала нужно установить сам language server для python. Для Arch/Manjaro установка будет выглядеть так:


sudo pacman -S python-language-server


С системными зависимостями разобрались. Приступаем к `init.el`. Будем использовать `use-package`, потому что не использовать его - это отстой. Но каждый решает сам.

Включаем `lsp-mode`. Да, для lsp нужно что-то, чем определить корневой каталог для проекта. Я использую везде projectile.


;; LSP settings
(use-package lsp-mode
:ensure t
:config
;; make sure we have lsp-imenu everywhere we have LSP
(require 'lsp-imenu)
(add-hook 'lsp-after-open-hook 'lsp-enable-imenu)
;; get lsp-python-enable defined
;; NB: use either projectile-project-root or ffip-get-project-root-directory
;; or any other function that can be used to find the root directory of a project
(lsp-define-stdio-client lsp-python "python"
#'projectile-project-root
'("pyls"))

;; make sure this is activated when python-mode is activated
;; lsp-python-enable is created by macro above
(add-hook 'python-mode-hook 'lsp-python-enable)

;; lsp extras
(use-package lsp-ui
:ensure t
:config
(setq lsp-ui-sideline-ignore-duplicate t)
(add-hook 'lsp-mode-hook 'lsp-ui-mode))

(use-package company-lsp
:config
(push 'company-lsp company-backends))

;; NB: only required if you prefer flake8 instead of the default
;; send pyls config via lsp-after-initialize-hook -- harmless for
;; other servers due to pyls key, but would prefer only sending this
;; when pyls gets initialised (:initialize function in
;; lsp-define-stdio-client is invoked too early (before server
;; start)) -- cpbotha
(defun lsp-set-cfg ()
(let ((lsp-cfg `(:pyls (:configurationSources ("flake8")))))
;; TODO: check lsp--cur-workspace here to decide per server / project
(lsp--set-configuration lsp-cfg)))
(add-hook 'lsp-after-initialize-hook 'lsp-set-cfg))


flake8, autopep8, fci, anaconda, rainbow-delimiters(я их везде юзаю):


;; Python mode hook
(defun my-python-mode-hook ()
"Define hook."

(use-package flymake-python-pyflakes
:config
(setq flymake-python-pyflakes-executable "flake8")
(setq flymake-python-pyflakes-extra-arguments '("--max-line-length=99"))
(flymake-python-pyflakes-load))

(use-package py-autopep8
:config
(setq py-autopep8-options '("--max-line-length=99"))
(py-autopep8-enable-on-save))

;; Enable rainbow
(use-package rainbow-delimiters)
(rainbow-delimiters-mode-enable)

(use-package highlight-indent-guides)
(use-package company)
(use-package anaconda-mode)
(use-package company-anaconda
:config
(add-to-list 'company-backends '(company-anaconda :with company-capf)))

(use-package flycheck-pyflakes
:config
(setq flychek-flake8-maximum-line-lenght 99))

(setq-default py-shell-name "ipython")
(setq-default py-which-bufname "IPython")
;; Fill column indicator
(use-package fill-column-indicator
:init
:config
(setq-default fill-column 99)
(setq fci-rule-width 1)
(setq fci-rule-color "#696969"))

(fci-mode)

(anaconda-mode +1)
(anaconda-eldoc-mode)
(highlight-symbol-mode +1)
(highlight-indent-guides-mode)
(company-mode))

(use-package python
:mode ("\\.py\\'" . python-mode)
:interpreter ("python" . python-mode)
:init
(add-hook 'python-mode-hook 'my-python-mode-hook))


Все!

Спасибо вот этому чуваку.

Ссылка: https://difrex.lessmore.pw/post/python-lsp/

# Рига
difrex.blog
Difrex(mobile)(tavern,23) — All
2018-07-30 07:40:49


Съездили тут на днях погулять в Латвию. Сели в машину и поехали. Границу пересекали в Бемякони, туда(к литовцам) въехали за два часа - нормалек.

Периодически шел дождь, но в целом погода была ничего.

## Рига

От границы до Риги дорога заняла часа 4-5. Старый город порадовал, красив.

Заехали на море(Рижский залив точнее). Пустынный солнечный пляж - это прикольно, но ледяной ветер не давал вдоволь насладиться видом и пробыли мы там всего минут 30.

Помимо Риги заезжали еще в несколько мест.

## Цесис

## Бауска

## Тракай

## Дорога обратно

По дороге обратно дождь чередовался с солнцем и было красиво.

Границу пересекли вечером за 3 часа. В Минск приехали уже в час ночи.

Ссылка: https://difrex.lessmore.pw/post/riga/

# Минск 08.05.2017
difrex.blog
Difrex(mobile)(tavern,23) — All
2018-07-30 07:40:49


Фотки без обработки, тупо RawTherapee -> export.

## Верхний город

## Центр

## Площадь независимости

Ссылка: https://difrex.lessmore.pw/post/minsk-08-05-17/

# Пилим i3wm
difrex.blog
Difrex(mobile)(tavern,23) — All
2018-07-30 07:40:49


Я тут на ЛОРе недавно постил скриншот и, вроде, людям понравилось. Попробую разобрать тут свой конфиг.

## Софт

Я использую Ubuntu 16.04, так что все действия актуальны для нее.

* i3-gaps

Это форк оригинального i3, где добавляются гапсы(отступы между окнами).

Сборку и установку производим так:


git clone https://github.com/Airblader/i3 -b 4.13
cd i3
dpkg-checkbuilddeps # проверяем какие зависимости нужно установить для сборки пакета, устанавливаем их.
dpkg-buildpackage -uc -us # собираем пакет
sudo dpkg -i ../i3-wm_4.13-1_amd64.deb # устанавливаем


* i3lock

Это блокировщик экрана. Ставим его из репозитория universe.

* compton

Тени, прозрачности и прочая красота. Так же ставим из официальных репозиториев.

* polybar

Панель, которую я использую в качестве замены стандартного i3bar.

Компиляем


git clone --branch 3.0.5 --recursive https://github.com/jaagr/polybar
mkdir polybar/build
cd polybar/build
cmake ..
make install


* rofi

Лаунчер. Так же ставим из репозиториев.

* feh

На самом деле - это просмотрщик изображений, но еще он позволяет установить обои.

* dunst

Уведомления(libnotify) рабочего стола.

## Конфигурация

Можно приступать к настройке WM.

~/.config/i3/config


# Клавиша super в качестве модификатора
set $mod Mod4
# Шрифты
font pango:hack 12
# Alt в качестве модификатора для управления плавающими окнами
floating_modifier Mod1
# Терминал
bindsym $mod+Return exec i3-sensible-terminal
# Закрытие окна
bindsym $mod+q kill

# Запуск лаунчера
bindsym $mod+d exec rofi -show run


Для настройки цветов лаунчера в ~/.Xresources пишем:


! ------------------------------------------------------------------------------
! ROFI Color theme
! ------------------------------------------------------------------------------
rofi.color-enabled: true
rofi.color-window: #393939, #393939, #268bd2
rofi.color-normal: #393939, #ffffff, #393939, #268bd2, #ffffff
rofi.color-active: #393939, #268bd2, #393939, #268bd2, #205171
rofi.color-urgent: #393939, #f3843d, #393939, #268bd2, #ffc39c


Hint: На сайте rofi можно найти несколько тем.

Локсрин. Я не использую комбинацию $mod+jklh для переключения между окнами, мне хватает стрелочек. Биндим i3lock на $mod+l.


# Lock desktop
bindsym $mod+l exec ~/.config/i3/lock.sh


Скрипт ~/.config/i3/lock.sh:


#!/bin/bash

# Make screenshot
scrot /tmp/screen.png

# Scale image
convert -scale 10% -scale 1000% /tmp/screen.png /tmp/screen1.png

# Clean
rm -f /tmp/screen.png

# Lock screen
i3lock -i /tmp/screen1.png


Выглядит это так:

Идем дальше по конфигу.


# Переключение между окнами:
bindsym $mod+Left focus left
bindsym $mod+Down focus down
bindsym $mod+Up focus up
bindsym $mod+Right focus right


Я пропущу дальше секции про управление окнами, т.к. конфиг практически ничем не отличается от дефолтоного. Удаляем/комментируем секцию с i3bar.

Убираем декорации окон


# New window size
new_window pixel


Мультимедиа кнопки


# Pulse Audio controls
bindsym XF86AudioRaiseVolume exec --no-startup-id pactl set-sink-volume 0 +5% #increase sound volume
bindsym XF86AudioLowerVolume exec --no-startup-id pactl set-sink-volume 0 -5% #decrease sound volume
bindsym XF86AudioMute exec --no-startup-id pactl set-sink-mute 0 toggle # mute sound

# Sreen brightness controls
bindsym XF86MonBrightnessUp exec xbacklight -inc 20 # increase screen brightness
bindsym XF86MonBrightnessDown exec xbacklight -dec 20 # decrease screen brightness


Настройка гапсов


# Эта опция нужна для того, чтобы гапсы отключались, если на эркане всего одно окно.
smart_gaps on

gaps inner 5
gaps outer 2


Автозапуск приложений


# Обои
exec feh --bg-scale /usr/share/backgrounds/gnome/Godafoss_Iceland.jpg &
# Автоблокировка экрана через 2 минуты
exec xautolock -locker ~/.config/i3/lock.sh -time 2 &
# Апллет для управления network-manager
exec nm-applet &
# Композитор
exec compton &
# Conky
exec conky -c /home/d_zheleztsov/.conkyrc &
# Почему-то без такого костыля у меня dunst запускаться не хочет
exec killall dunst && dunst -conf /home/d_zheleztsov/.config/dunst &

# Изменение цветовой температуры в зависимости от времени суток
exec redshift &

# Запускаем приложения на своих рабочих столах
exec --no-startup-id i3-msg 'workspace 1; exec firefox'
exec --no-startup-id i3-msg 'workspace 2; exec gnome-terminal'
exec --no-startup-id i3-msg 'workspace 3; exec emacs25'
exec --no-startup-id i3-msg 'workspace 4; exec pidgin'
exec --no-startup-id i3-msg 'workspace 5; exec evolution'

# Панель
exec ~/.local/bin/polybar main &


По поводу конфигурации панели будет хорошо почитать официальную вики.

## Итоговые конфиги

* i3: ~/.config/i3/config
* polybar: ~/.config/polybar/config
* conky: ~/.conkyrc

## Что получилось

Ссылка: https://difrex.lessmore.pw/post/i3wm-config/

# Фест Эпоха рыцарства 2017
difrex.blog
Difrex(mobile)(tavern,23) — All
2018-07-30 07:40:48


Будет много фоток. Пост весит 16Мб.

Под Минском в д. Озерцо проходил фестиваль "Эпоха рыцарства" на котором в первый день я и побывал.

Было солнечно и тепло. В палатках продовались домашняя медовуха и сбитень.

Уже на подходе к самому месту проведения заметили палатки и косплееров на коняшках.

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

Во второй половине дня начался турнир рыцарей. Это там, где они пиками друг-друга тыкают. Ведущий что-то постоянно рассказывал и комментировал.

Вышли сами рыцари с флагами и на конях.

Вот этот с гусем на голове был особо приколен.

Над этим всем летал дрон и снимал видео. Наверное, его где-то можно будет увидеть.

Рыцари скакали на лошадях и перепрыгивали через препятствие. Весело.

Высоко в небе периодически летали дельтопланы с которых тоже фотографировали фестиваль.

В конце турнира по сценарию рыцари поссорились и между ними начался махач.

За этим наблюдали красивые девочки в средневековых костюмах.

Вечером, на разогреве, выступали фолк-музыканты. Первыми вышли Hardwood.

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

Следующими выступали Стары Ольса. Подтянулись мужики в смешных шапках. Наверняка гномы.

Выступление проходило весело.

Барабанщики круты!

После Стары Ольса на сцену вышли Butterfly Temple. Пока они чекались сходил за сцену.

Клевые домики.

Средневековые девченки отошли за сцену покурить и початиться.

Наконец-то Butterfly настроились и зарубили МИТОЛ!

Чувак-ведущий залез на столб и пустился в пляс!

Выступление было драйвовым. Играли Butterfly Temple примерно час. На улице стемнело и температура воздуха опустилась всего до 12 градусов тепла. Комары озверели, в шортах находиться стало не очень круто и мы поехали домой в Минск.

Ссылка: https://difrex.lessmore.pw/post/fest-folk-museum/

# Отправляем логи в удаленный logstash
difrex.blog
Difrex(mobile)(tavern,23) — All
2018-07-30 07:40:47


Все привыкли пользоваться связкой ELK. А что делать, если хочется отправить логи в уже существующий ELK с хоста на котором памяти в обрез?

У меня получилось так, что на виртуалке с сайтиком всего 512Мб памяти и логстешь при запуске просто выжирал ее всю и падал. Никакие Xmx Xms не помогали. Самое интересное, что логи-то nginx я заставил писать в JSON, а значит logstash выступает просто проксей до эластика.

Вот так можно заставить писать nginx в JSON. Добавляем это в nginx.conf.


log_format logstash_json '{ "@timestamp": "$time_iso8601", '
'"remote_addr": "$remote_addr", '
'"remote_user": "$remote_user", '
'"body_bytes_sent": "$body_bytes_sent", '
'"request_time": "$request_time", '
'"status": "$status", '
'"request": "$request", '
'"request_method": "$request_method", '
'"http_referrer": "$http_referer", '
'"http_user_agent": "$http_user_agent" }';



А в конфиге сайта


access_log /var/log/nginx/access.log logstash_json;


Собственно пишем конфиг удаленного логстеша:


input {
tcp {
port => 12222
host => "10.8.0.10"
codec => "json"
}
}

output {
elasticsearch {
index => "nginx"
}
}


Теперь делаем скрипт отправки логов:


#!/bin/bash

# /usr/local/bin/logsend.sh

/usr/bin/tail -f /var/log/nginx/access.log | /bin/nc 10.8.0.10 12222


И запиливаем сервис systemd и стартуем его


[Unit]
Description=Send nginx log to remote logstash

[Service]
Type=simple
ExecStart=/usr/local/bin/logsend.sh

[Install]
WantedBy=multi-user.target


systemctl status logsend


● logsend.service - Send nginx log to remote logstash
Loaded: loaded (/etc/systemd/system/logsend.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2017-09-02 12:05:01 UTC; 1h 33min ago
Main PID: 28559 (logsend.sh)
Tasks: 3
Memory: 484.0K
CPU: 12ms
CGroup: /system.slice/logsend.service
├─28559 /bin/bash /usr/local/bin/logsend.sh
├─28562 /usr/bin/tail -f /var/log/nginx/access.log
└─28563 /bin/nc 10.8.0.10 12222


Использование памяти пол-мегабайта :).

Ссылка: https://difrex.lessmore.pw/post/logs-to-remote-logstash/

# Go в GNU Emacs
difrex.blog
Difrex(mobile)(tavern,23) — All
2018-07-30 07:40:47


На самом деле это выжимка вот этой статьи. Ну, а еще некоторые вещи в ней устарели, по-этому немного обновленная версия.

# tl;dr

Поставим нужные пакеты в Емакс


(use-package exec-path-from-shell)
(use-package rainbow-delimiters)
(use-package go-snippets)
(use-package go-guru)
(use-package go-autocomplete)


Настроим go-mode


(use-package go-mode
;; Godef jump key binding
:bind (("M-." . godef-jump)
("M-*" . pop-tag-mark))
:init
(setenv "GOPATH" (concat (getenv "HOME") "/.local"))
:config
(defun set-exec-path-from-shell-PATH ()
(let ((path-from-shell (replace-regexp-in-string
"[ \t\n]*$"
""
(shell-command-to-string "/bin/bash -c '. ~/.bashrc && echo $PATH'"))))
(setenv "PATH" path-from-shell)
;; (setq eshell-path-env path-from-shell) ; for eshell users
(setq exec-path (split-string path-from-shell path-separator))))

(when window-system (set-exec-path-from-shell-PATH))

(defun my-go-mode-hook ()
"My Golang hook."
(setq gofmt-command "goimports")

;; Call Gofmt before saving
(add-hook 'before-save-hook 'gofmt-before-save)

;; Set compile command
(if (not (string-match "go" compile-command))
(set (make-local-variable 'compile-command)
"go build -v && go test -v && go vet"))

;; Enable rainbow
(rainbow-delimiters-mode-enable)
(auto-complete-for-go)
(yas-initialize))

;; Go autocomplete
(defun auto-complete-for-go ()
"Enable golang autocomple."
(auto-complete-mode 1))

(add-hook 'go-mode-hook 'auto-complete-for-go)
(add-hook 'completion-at-point-functions 'go-complete-at-point)
(add-hook 'go-mode-hook 'my-go-mode-hook)
(add-hook 'go-mode-hook #'rainbow-delimiters-mode))


Тут в :bind можно прописать свои сочетания клавиш.

Да, всегда используйте use-package. Это сэкономит кучу времени в будущем.

Теперь добавим GOPATH в ~/.bashrc


echo 'export GOPATH=${HOME}/.local' >> ~/.bashrc
. ~/.bashrc


Выкачиваем зависимости Go


go get -t -v golang.org/x/tools/cmd/goimports
go get -t -v golang.org/x/tools/cmd/guru
go get -t -v github.com/rogpeppe/godef


Готово. Код конфига доступен по ссылке.

Ссылка: https://difrex.lessmore.pw/post/go-v-emacs/

# API поиска на dynamic.lessmore.pw
difrex.blog
Difrex(mobile)(tavern,23) — All
2018-07-30 07:40:46


## Поиск на dynamic.lessmore.pw

Как это ваще устроено??? На самом деле API - это открытый всем Elasticsearch, который предоставляет гору возможностей для поиска за счет движка Lucene. Давайте что-нибудь найдем!

Вот в этом вот комменте я пообещал рассказать как это все сделать. Приступим.

Давайте для начала попробуем поискать этот самый коммент: ii://XWShDDcuR4C8PcrTFdGl. Здесь и далее мы будем использовать только curl.


curl -XPOST -d '{"query": {"query_string" : {"fields" : ["msgid"], "query" :"XWShDDcuR4C8PcrTFdGl"}}}' https://dynamic.lessmore.pw/search


Нам вернется такой вот ответ


{
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 8.316952,
"hits": [
{
"_index": "idec_net",
"_type": "post",
"_id": "XWShDDcuR4C8PcrTFdGl",
"_score": 8.316952,
"_source": {
"echo": "idec.talks",
"subg": "Re: Совет нодов",
"to": "Peter",
"author": "Difrex(mobile)",
"message": "\nПостараюсь завтра написать пост с обзором в ii://develop.16. Ну, и ссылку в этот тред скину.",
"date": "1513020107",
"msgid": "XWShDDcuR4C8PcrTFdGl",
"tags": "",
"repto": "h97Frgqdtapl4AI11aUj",
"address": "tavern,23"
}
}
]
}
}


Вот и он!

Нам вернулось одно сообщение, что не удивительно, т.к. ID в сети уникальны, а мы искали именно по нему.

А теперь давайте выведем все последние(5) сообщения(по дате) из эхи idec.talks:


curl -XPOST -d '{"sort": [{"date": {"order": "desc"}}, {"_score": {"order": "desc" }}], "size": 5}' https://dynamic.lessmore.pw/search -H 'Content-type: application/json'
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
}
...


Смотрите, тут мы отсортировали(на стороне сервера) сообщения по дате в порядке убывания и ограничили лимит в 5 сообщений. Попробуйте перевести это на SQL(`select * from idec.talks order by date desc limit 5`).

А теперь выполним более сложный поиск: мы найдем сообщения по строке! Т.е. выполним полнотекстовый поиск!

Запрос будет выглядеть так:


{
"sort": [
{
"date": {
"order": "desc"
}
},
{
"_score": {
"order": "desc"
}
}
],
"query": {
"simple_query_string": {
"query": "обзор"
}
},
"size": 5
}


Отправляем его POST-ом в https://dynamic.lessmore.pw/search.

В ответ нам на это вернется список из 5 сообщений отсортированных по дате, где найдены вхождения слова "обзор". Кстати, верхнее сообщение(b2rhH6sOfzEzgGZzLT51(на данный момент)) из эхи habra.16 и с заголовком "Обзор литературы по языку Python для начинающих".

Вот так вот. Чтобы делать более лучшие вещи читайте документацию(query DSL) по Elasticsearch.

// Да, если вашей эхи нет в индексе, то убедитесь, что она есть в list.txt

Ссылка: https://difrex.lessmore.pw/post/api-poiska-na-dynamic/

# Про IDEC
difrex.blog
Difrex(mobile)(tavern,23) — All
2018-07-30 07:40:42


IDEC - это протокол обмена сообщениями совместимый на базовом уровне с ii. Расшифровывается, как ii-like Data Exchange Convention. Главная фишка его - это простота и возможность работать поверх чего угодно, например, ssh. Но практически все реализации сейчас работают поверх http.

Цитата из официальной документации

> Есть несколько серверов (грубо говоря, сайтов), за каждым из которых закреплены свои пользователи (поинты). Поинты пишут сообщения каждый на свой сервер. Через каждые 10-20 минут сервера скачивают друг у друга новые сообщения. В итоге на всю сеть одна общая база данных. Для установления цепочек синхронизации владельцы серверов сначала договариваются.
>
> Всё общение разделено на так называемые эхоконференции или эхи (см. терминология). Эха - это что-то вроде ленты твиттера или темы на форуме. Пользователи могут свободно подписываться на интересные им эхи и писать туда сообщения в пределах одной станции. Держатели серверов синхронизируют между собой (по общему согласию) самые популярные и нужные пользователям эхи, и сообщения оттуда расходятся по всей сети.

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

## Общение

В стандарте предусмотрена очень полезная фича, как /list.txt(это может быть на самом деле файл или путь в строке адреса в браузере). На запрос list.txt сервер возвращает нам список эх(публичных) с описанием и количеством сообщений в них. Так при первом попадании на сервер, клиент сможет сразу знать какие эхи он хочет читать.

Стандарт и все реализации серверов поддерживают создание эхи пользователем. Для этого нужно всего лишь написать в нее. Такая эха не будет отображаться в list.txt и получить из нее сообщения можно, только зная название. Шифрования в стандарте нет, но это и не нужно, ибо приносит только усложнение. Для приватного общения можно использовать скрытую эху и GPG.

Личных сообщений нет, но обсуждение стандарта идет. Можно начать с чтения этого треда.

Каждое сообщение в сети уникально, т.е. ему присвается ID сгенерированный на основе суммы sha256 от контента. Это не спасает от спама, но позволяет избежать коллизий в сети.

## Устройство сети

На протоколе IDEC чаще всего реализуют децентрализованную клиент-сервер сеть. P2P не предусмотрено, но никто не мешает написать свое расширение, которое реализует P2P обмен.

Итак, рассмотрим топологию сети от простого к сложному.

Самая простейшая сеть выглядит так:

У нас есть два клиента, которые обмениваются сообщениями через сервер. Оба клиента получают сообщения из одной и той же эхи. Все централизовано и при смерти сервера клиенты больше не смогут общаться с друг дугом. Давайте добавим еще один сервер!

Владельцы серверов договорились между собой обмениваться сообщениями эхи pipe.2032, теперь при выходе из строя одного из серверов сообщения будут доступны на другом сервере.

Добавим еще сегмент сети

У нас добавился еще один сегмент сети в котором происходит общение в эхах pipe.2032 и linux.14. Так наш первый сегмент начинает обмениваться сообщениями со вторым. Добавим еще один сегмент.

И еще

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

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

В следующей статье напишем бота, который будет слать сообщения в указанную нами эху.

Ссылка: https://difrex.lessmore.pw/post/pro-idec/

# eshell в качестве шелла
difrex.blog
Difrex(mobile)(tavern,23) — All
2018-07-30 07:40:39


Я тут подумал: а чей-то я использую в качестве шелла zsh, когда можно юзать емаксовый eshell?

Быстренький гайд.

## Делай раз

Для начала, чтобы темы отображались правильно нужно сгенерировать terminfo. В 26.1 емаксе можно работать с 24-битным терминалом. Напишем файл terminfo-24.src:


# Use colon separators.
xterm-24bit|xterm with 24-bit direct color mode,
use=xterm-256color,
setb24=\E[48:2:%p1%{65536}%/%d:%p1%{256}%/%{255}%&%d:%p1%{255}%&%dm,
setf24=\E[38:2:%p1%{65536}%/%d:%p1%{256}%/%{255}%&%d:%p1%{255}%&%dm,
# Use semicolon separators.
xterm-24bits|xterm with 24-bit direct color mode,
use=xterm-256color,
setb24=\E[48;2;%p1%{65536}%/%d;%p1%{256}%/%{255}%&%d;%p1%{255}%&%dm,
setf24=\E[38;2;%p1%{65536}%/%d;%p1%{256}%/%{255}%&%d;%p1%{255}%&%dm,


Генерируем:


tic -x -o ~/.terminfo terminfo-24bit.src


Экспортируем переменную окружения:


export TERM=xterm-24bit


Теперь при запуске GNU Emacs в терминале(`emacs[client] -nw`) вместо покореженных цветов при `TERM=xterm-256color`

будет красиво

Это тема solarized-dark, кстати.

## Делай два

Но запускать Емакс в терминале при наличии иксов несколько странно. По-этому нужно пускать сразу `(eshell)`. В параметрах терминала в качесте комманды прописываем `/bin/sh -c "export TERM=xterm-24bit; emacsclient -nw -c -e \"(eshell 'N)\""` и у нас будет сразу пускаться eshell. Неплохо, не правда ли? :)

Либо можно пойти еще дальше и перебиндить стандартнуй комбинацию клавишь на запуск сразу eshell в графическом Emacs. Так, например, для i3wm: `bindsym $mod+Return exec emacsclient -c -e "(eshell 'N)"`.

Ура!

Ссылка: https://difrex.lessmore.pw/post/eshell/