LINUX.ORG.RU

[Emacs] hs-minor-mode

 


0

1

может он сохранять состояние? если нет, то может кто нибудь напишет функцию, которая бы это делала. заранее большое спасибо

Ответ на: комментарий от ott

ну к примеру можно условиться о специальном файле, я думаю не сложно будет носить килобайтный файлик в проекте) или какой нибудь комментарий, найдя который в блоке кода, она будет скрывать этот код. Я думаю знатоку elisp будет пару минут накатать такой функционал

pseudo-cat ★★★
() автор топика

Долго объяснять. Самый быстрый вариант у меня получился такой: я тупо собираю нужные оверлеи по файлу, сохраняю координаты их начала в виде списка в файл с дополнительный расширением .hs (на каждый текстовый файл свой). Соответсвенно, при восстановлении иду по списку по сохраненным координатам и делаю в этом месте hide. Если спрятанных участков нет, то файл не создается. У способа есть недостатки, которые обусловлены недостатком режима.

(defun hs-save-state (filename)
  (let ((overlays nil))
    (dolist (ov (overlays-in (point-min) (point-max)))
      (when (overlay-get ov 'hs)
	(setq overlays (cons (overlay-start ov) overlays))))
    (if overlays
	(with-temp-file filename
	  (prin1 overlays (current-buffer)))
      (when (file-exists-p filename)
	(delete-file filename)))))
	
(defun hs-restore-state (filename)
  (when (file-exists-p filename)
    (let ((overlays
	   (read (with-temp-buffer
		   (insert-file-contents-literally filename)
		   (buffer-string)))))
      (when (listp overlays)
	(save-excursion
	  (mapc '(lambda (pos) 
		   (goto-char pos)
		   (hs-hide-block))
		overlays))))))

Не тестировал! Пару раз попробовал, высылаю как есть. Тупой способ использования ниже. Тупой, потому что при каждом скрытии блока обновляет файл состояния, однако это может происходить относительно быстро и не так анноить. Более интеллигентные варианты требуют времени (которого нет). Названия файлов для сохранения состояния можешь сам себе придумать.

(setq hs-hide-hook (lambda () 
		     (hs-save-state (concat (buffer-name) ".hs"))))

;;(setq hs-show-hook (lambda () 
;;		     (hs-save-state (concat (buffer-name) ".hs"))))

(setq hs-minor-mode-hook
      '(lambda () 
	 (if hs-minor-mode
	     (hs-restore-state (concat (buffer-name) ".hs")))))

Очевидный недостаток: переправил файл в другом редакторе — все поползло, так как рассинхронизация произойдет. Ситуацию можно чуточку, наверное, улучшить, если сохранять не начало оверлея, а скажем середину между overlay-start и overlay-end. Тогда, может быть, несколько вставленных переводов строки меньше скажутся на рассинхронизации. Второй недостаток (блин, очень много писать) - это то, что хук hs-show-hook вызывается при выходе из режима hs-minor-mode (так как автоматом вызывается hs-show-all), поэтому обновление файла в этом хуке я не делал (закомментировано в примере). То есть если ты раскроешь какой-то блок, то информация о нем не сохранится, пока ты либо не свернешь какой-то другой блок, либо ты вручную или по таймеру не вызовешь hs-save-state (типа автосохранения через промежутки времени). Короче, тут надо подумать.

Я думаю, что можно написать по-другому, это уже по ходу дела идейки пришли, но мне не хочется их делать. Можно базироваться не на оверлеях, а сохранять в хуке hs-hide-hook позицию, где ты попросил свернуть блок. Но тогда надо усиленно подумать, как удалять эту позицию, когда ты опять раскрыл блок. Ведь раскрыть блок ты можешь, находясь в другой позиции, которая отличается от сохраненной. Нужно подумать над алгоритмом, как правильно удалять из списка старые, ненужные позиции (можно использовать данные из оверлеев или диапазоны начало-конец сохранять).

Идея с тегами (специально составленными комментариями в тексте программы на языке программы) кажется разумной, потому что тогда не будет рассинхронизации. Но в тексте от этих тегов будет мусор. Можно еще как варинат рассмотреть возможность расстановки каких-нибудь реперных точек по тексту, а координаты запоминать относительно них.

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

Сегодня еще раз глянул, что написал. Оказалось, что в Emacs 22 хук hs-show-hook не работает как надо. По документации он всегда должен вызываться при toggle, hs-show-block и hs-show-all, а он вызывается только после hs-show-all. Глянул в исходники hideshow.el. Мне действительно кажется, что там баг. Хук там есть, но до него дела никогда не доходит, не срабатывает он у меня. Не знаю, исправлено ли что-то в последующих версиях Emacs.

Если хук работает сейчас в Emacs23/24, то его можно раскомментировать. Но при работе помнить одну только вещь — не выходить из режима при помощи выключения hs-minor-mode, не менять режим буфера, а просто закрывать буфер. Если выключить режим, то перед вызовом хука hs-minor-mode-hook всегда принудительно вызывается hs-show-all. Сделать с этим ничего нельзя (ну, если только хачить hideshow.el). Как отличить по косвенным признакам, ручное раскрытие всех блоков пользователем и финальное автоматическое раскрытие, я пока не придумал. Просто финальный автоматический вызов hs-show-all запишет текущие оверлеи, а они все уже будут удалены после hs-show-all.

И еще, возможно, лучше записывать в файл не начало оверлея, а (1+ (overlay-start ov)).

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

>Глянул в исходники hideshow.el. Мне действительно кажется, что там баг. Хук там есть, но до него дела никогда не доходит, не срабатывает он у меня. Не знаю, исправлено ли что-то в последующих версиях Emacs.

Ага, точно баг. Исправили уже.

http://permalink.gmane.org/gmane.emacs.bugs/31481

Zubok ★★★★★
()
Ответ на: комментарий от pseudo-cat

>большое спасибо, то что надо.

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

А может им в стандартную поставку это добавить?

Чтобы добавить такое, надо посерьезнее отнестись к делу, так как способов решения задачки может быть несколько (то же тегирование как альтернатива).

К тому же, сейчас я со своей стороны ничего не могу добавить в Emacs, так как для этого FSF требует подписания copyright assignment papers. Я месяц назад отправил запрос на бумаги, а они так и не пришли. Я попросил FSF подтвердить, что бумаги отправленв, а они, оказывается, запроса с заполненным вопросником не получили. Пришлось с другого ящика выслать. Надеюсь, что в этот раз получили. Теперь надо ждать, когда бумаги приедут сюда, потом я их подпишу, отправлю назад. Без этой процедуры никакие мои патчи в транк брать не будут. Берут только тривиальные патчи меньше 10 строк.

Zubok ★★★★★
()
Ответ на: комментарий от pseudo-cat

>ок

Вот баг уже выцепил. Если скрыть что-то, а потом просто отбить переводами строк (достаточно большим количеством), то Emacs это отслеживает, а вот в файл *.hs изменения не попадают. Соотвестственно, рассинхронизируется все. Надо пнуть Emacs, чтобы при изменениях сдампил снова. Разумно повесить hs-save-state на хук сохранения буфера. Если ты отбиваешь текст RETом или что-то добавляешь, то у буфера сразу поменяется флаг, что он был изменен. Это неизбежно заставит Emacs тебя предупреждать перед закрытием, что файл был изменен и надо сохранить, сработает хук и все новые значения координат сохранятся.

При этом можно даже отказаться от того, чтобы вешать на хуки hide и show сохранение *.hs (hs-save-state). Можно просто выставлять в этих хуках флаг, что файл в буфере изменен (то есть будем считать, что скрытие кода и раскрытие — это изменение. Не так кузаво, конечно, но зато в файл при каждом чихе дампить не надо будет). Тогда Emacs при закрытии буфера будет предлагать сохранить файл. Заодно и состояние hideshow сохранится. Вот тут надо подумать, есть ли смысл так делать.

Zubok ★★★★★
()
Ответ на: комментарий от pseudo-cat

Примерно так:

(setq hs-hide-hook (lambda () (set-buffer-modified-p t)))
(setq hs-show-hook (lambda () (set-buffer-modified-p t)))

(add-hook 'after-save-hook 
	  (lambda () 
	    (if hs-minor-mode
		(hs-save-state (concat (buffer-name) ".hs")))))

(setq hs-minor-mode-hook
      '(lambda () 
	 (if hs-minor-mode
	     (hs-restore-state (concat (buffer-name) ".hs")))))

Можно еще глянуть на другие хуки типа write-contents-functions, write-file-functions

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

И лучше использовать не buffer-name, а buffer-file-name.

Zubok ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.