Я выступаю с докладом о программировании. Вместо того, чтобы использовать слайды, я представляю последовательность постепенно увеличивающихся программ, хранящихся в именах файлов 0001.py
, 0002.py
и т. д.
Код в каждой программе представляет собой всего одну или несколько строк кода в качестве модификации предыдущей.
Я намерен представить исключительно с использованием emacs. Я знаком с ediff
, но было бы немного неудобно использовать его вживую во время выступления (поскольку существует около 50 небольших программ, каждая из которых занимает одну минуту).
Существует ли пакет emacs, который позволил бы мне разделить окно и выделить то, что на самом деле отличается между (n).py и (n+1).py. (Я использую .py
для конкретики, но, надеюсь, решение будет работать для любого текстового файла.)
Я спрашиваю здесь, а не на https://emacs.stackexchange.com, потому что я буду доволен решением, использующим emacs, git или любую комбинацию, которую я могу объединить, чтобы дать живую демонстрацию, особенно с возможностью изменять код вживую, отвечая на вопросы.
Обновлять
Как предполагает phils
, M-x
compare-windows
почти решает эту проблему, но:
diff
s. Суть в том, чтобы сказать: «Посмотрите, в программе справа я добавил только эту строку и эту строку, и посмотрите на все, что может сделать программа это по сравнению с предыдущей».Обновление 2
Другими словами, как мне сгенерировать то, что делается вручную в приведенном ниже HTML, чтобы показать различия рядом друг с другом?
.myflex {
display: flex;
flex-direction: row;
}
.before,
.after {
border: 1px solid black;
padding: 20px;
margin: 20px;
border-radius: 2px;
}
.pink {
background-color: pink;
}
.green {
background-color: PaleGreen;
}
<div class = "myflex">
<div class = "before">
<pre>
<span class='pink'>And so without particularly analyzing all the contiguous sections of a</span>
<span class='pink'>cone and of the ranks of an army, or the ranks and positions in any</span>
while the less their direct participation in the action itself, the more
they command and the fewer of them there are; rising in this way from
the lowest ranks to the man at the top, who takes the least direct share
in the action and directs his activity chiefly to commanding.
</pre>
</div>
<div class = "after">
<pre>
<span class='green'>We see a law by which men, to take associated action, combine</span>
<span class='green'>in such relations that the more directly they participate in performing</span>
<span class='green'>the action the less they can command and the more numerous they are,</span>
while the less their direct participation in the action itself, the more
they command and the fewer of them there are; rising in this way from
the lowest ranks to the man at the top, who takes the least direct share
in the action and directs his activity chiefly to commanding.
</pre>
</div>
</div>
Продолжение
(Я добавляю это продолжение сюда только потому, что Филс великодушно вызвался ответить на больше, чем я изначально просил.)
Рассмотрим программу (на каком-то воображаемом языке, хранящуюся в .txt
файле):
hello
и учтите, что мы вставляем ключевое слово, требующее отступа:
repeat:
hello
Теперь, когда мы показываем две программы в разделенном окне, было бы неплохо, если бы hi
была выделена нет, несмотря на то, что две строки отличаются отступом; только repeat:
есть.
Идея состоит в том, что мы добавляем какой-то оператор цикла и не хотим, чтобы взгляд слушателя переходил на либо отступ или на всю строку, только на оператор.
Другими словами, при отображении разницы мы бы в идеале выделяли строку repeat
, но не hello
и предшествующий ей отступ.
@филс Да! Вот почти все. Добавлю к сути вопроса.
Почему неудобно использовать ediff
или M-x diff
? Пожалуйста, уточните, что вам нужно, на что они не отвечают.
вы можете поместить свои изменения в последовательные ветки git и использовать magit-ediff
@Drew ediff
/diff
покажет различия один за другим. Мне нужно повторить, чтобы показать, что они собой представляют. Я бы хотел, чтобы различия были выделены (в виде transient-region
или любого другого маркера), чтобы привлечь внимание слушателя к этим сегментам.
diff
показывает все отличия - показывает дифф (только), т.е. патч. В любом случае, пожалуйста, укажите в вопросе, что именно вас интересует - комментарии могут быть удалены в любое время. Спасибо.
Я подозреваю, что некоторые существующие функции diff
могут сделать это, поэтому будет лучший ответ, но я взломал следующее вместе, используя compare-windows
.
(defun my-compare-windows-complete (&optional ignore-whitespace)
"Highlight all differences between two windows.
With a prefix argument, do not highlight whitespace-only differences.
\(This does not prevent the highlighting of whitespace that is part of
a difference which includes non-whitespace characters.)
To remove the highlighting, use \\[compare-windows-dehighlight]."
(interactive "P")
(require 'cl-lib)
(require 'compare-w)
(compare-windows-dehighlight)
(let ((w1 (get-buffer-window))
(w2 (funcall compare-windows-get-window-function)))
(cl-letf ((w1p (window-point w1))
(w2p (window-point w2))
(compare-windows-highlight 'persistent)
((symbol-function 'compare-windows-dehighlight) #'ignore)
((symbol-function 'ding) (lambda () (error "done"))))
(with-selected-window w1
(goto-char (point-min)))
(with-selected-window w2
(goto-char (point-min)))
(ignore-errors
(while (compare-windows ignore-whitespace)))
;; Highlight any non-matching remainder in both buffers.
(let ((b1 (window-buffer w1))
(b2 (window-buffer w2))
(p1 (window-point w1))
(p2 (window-point w2))
(max1 (with-selected-window w1 (point-max)))
(max2 (with-selected-window w2 (point-max))))
(compare-windows-highlight p1 max1 b1 w1 p2 max2 b2 w2))
(set-window-point w1 w1p)
(set-window-point w2 w2p))))
После этого вы можете использовать M-xcompare-windows-dehighlight
, чтобы убрать выделение.
Лица, используемые для выделения:
compare-windows-removed
(наследуется от diff-removed
)compare-windows-added
(наследуется от diff-added
)Хороший!! Это делает это. Проблема для (будущего) вопроса о продолжении будет состоять в том, чтобы изменить определение «diff», чтобы оно игнорировало отступ. Например, если я оборачиваю конструкцию начала-конца цикла вокруг блока кода, блок получает отступ, что дает нежелательный визуальный сигнал от выделения о том, что тело цикла изменилось, хотя новыми являются только оболочки.
Впоследствии я добавил поведение аргумента префикса, которое касается проблемы отступа, которую вы описали (используя существующий аргумент ignore-whitespace
для compare-windows
); и я исправил то, что считал ошибкой, добавив выделение любого несоответствующего текста в конце буфера (впоследствии до конечной совпадающей области). Я думаю, что с этими дополнениями это работает довольно хорошо (хотя и не слишком быстро для большого количества различий).
Это очень мило. Но ваша модификация еще не идеальна :). Я добавил продолжение к вопросу. Вы не обрабатываете часть "либо". (Или, более подробно, теперь вы обрабатываете часть «вся строка», а не часть «либо отступ, либо».)
Мы находимся на территории «именно так compare-windows
работает». Попробуйте это со своим тестовым случаем, и вы увидите, что он вообще не считает, что между двумя окнами есть какое-либо сходство. Таким образом, моя функция затем выделяет все в каждом окне (в каждом случае это «конечный несоответствующий текст в конце»). Если вы хотите, чтобы это изменилось, для самого compare-windows
потребуется патч восходящей ветки.
Экспериментально мне кажется, что «привет» — это просто слишком короткий текст для compare-windows
рассмотрения. Увеличение его как минимум до четырех символов делает то, что вы хотели (с оговоркой «Это не препятствует выделению пробелов, которые являются частью различия, которое включает символы, отличные от пробелов»).
Отступ остается выделенным после увеличения длины слова. Я добавил изображение для иллюстрации.
Действительно - согласно цитируемой оговорке из моего предыдущего комментария. Опять же, это просто то, как работает compare-windows
.
Начиная с точки в начале каждого из двух буферов, повторный вызов
compare-windows
будет проходить через различия. Это работает для вашего варианта использования?