Привет всем,
Если кто-то разбирается в xi-editor, объясните плз следующую странность.
Я разработчик консольного клиента (фронтенда) к xi-editor. Заморочился вопросом реализовать частичную перерисовку экрана (например при движении курсора на 1 строку вниз надо перерисовать только старую и новую строку, а не все строки) при получении notification от xi-editor. Сейчас на каждый чих происходит полная перерисовка и это приводит к некрасивому миганию экрана.
Так вот, проблема в том, что уведомление о перемещении курсора является частью операции insert:
interface Op {
op: "copy" | "skip" | "invalidate" | "update" | "ins"
n: number // number of lines affected
lines?: Line[] // only present when op is "update" or "ins"
}
interface Line {
text?: string // present when op is "update"
ln?: number // the logical/'real' line number for this line.
cursor?: number[] // utf-8 code point offsets, in increasing order
styles?: number[] // length is a multiple of 3, see below
}
В результате, когда я перемещаю курсор вниз на 1 позицию со строки «aaa» на строку «bbb», вот какие нотификации приходят от xi-core:
-
copy nb_lines=12 (скопировать 12 строк перед курсором из старого кэша в новый - ничего не меняется)
-
ins nb_lines=2 (вставить 2 новых строки)
- line: aaa
- line: bbb cursor=0 (курсор в начало bbb)
- skip nb_lines=2 (пропустить 2 строки в старом состоянии)
- line: aaa cursor=0 (курсор был в начале aaa)
- line: bbb
- copy nb_lines = 33 (взять оставшиеся строки из старого кэша)
И это реально жесть. Мне приходит набор операций в виде вектора ops. По нему я очень быстро должен понять, был ли обновлён выводимый текст (не курсор). Позиция курсора в клиенте совершенно логично хранится отдельно от кэша самих строк и он, совершенно логично, рендерится отдельно поверх строк (termion::cursor::Goto). Как я блин пойму, что операция ins + skip на самом деле всего лишь обновила курсор, а текст не трогала?
Причём в спеке чёрным по белому сказано, что для нотификаций о курсоре предназначен оператор update:
In an «update» op, then the text property is absent from the line, and text is copied from the previous state (or left invalid if the previous state is invalid), and the cursor and styles are updated if present. To delete cursors from a line, the core sets the cursor property to the empty list.