Emacs — изменить `dired-mark`, чтобы предотвратить перемещение курсора на пустую строку в eob

#emacs #elisp #dired

#emacs #elisp #dired

Вопрос:

У меня есть пользовательская функция, которая получает имена файлов с пометкой dired (т. Е. Имена каждого отмеченного файла), если отмечено более одного, или если только один, он получает имя файла в точке. Проблема возникает всякий раз, когда курсор находится на ничейной территории, потому dired-mark что (или я, потому что я пилот) переусердствовал с повторением и перемещает курсор на пустую строку в конце буфера, где нет файла. В этой ситуации ошибка заключается в следующем:

 Debugger entered--Lisp error: (error "No file on this line")
  signal(error ("No file on this line"))
  error("No file on this line")
  dired-get-file-for-visit()
  (file-directory-p (dired-get-file-for-visit))
  (if (file-directory-p (dired-get-file-for-visit)) nil (let ((lawlist-filename (if (or (re-search-backward "^*" nil t) (re-search-forward "^*" nil t)) (dired-get-marked-files) (dired-get-file-for-visit)))) (wl-draft-mailto) (attach-multiple-files lawlist-filename)))
  (lambda nil (interactive) (if (file-directory-p (dired-get-file-for-visit)) nil (let ((lawlist-filename (if (or (re-search-backward "^*" nil t) (re-search-forward "^*" nil t)) (dired-get-marked-files) (dired-get-file-for-visit)))) (wl-draft-mailto) (attach-multiple-files lawlist-filename))))()
  funcall-interactively((lambda nil (interactive) (if (file-directory-p (dired-get-file-for-visit)) nil (let ((lawlist-filename (if (or (re-search-backward "^*" nil t) (re-search-forward "^*" nil t)) (dired-get-marked-files) (dired-get-file-for-visit)))) (wl-draft-mailto) (attach-multiple-files lawlist-filename)))))
  call-interactively((lambda nil (interactive) (if (file-directory-p (dired-get-file-for-visit)) nil (let ((lawlist-filename (if (or (re-search-backward "^*" nil t) (re-search-forward "^*" nil t)) (dired-get-marked-files) (dired-get-file-for-visit)))) (wl-draft-mailto) (attach-multiple-files lawlist-filename)))) nil nil)
  command-execute((lambda nil (interactive) (if (file-directory-p (dired-get-file-for-visit)) nil (let ((lawlist-filename (if (or (re-search-backward "^*" nil t) (re-search-forward "^*" nil t)) (dired-get-marked-files) (dired-get-file-for-visit)))) (wl-draft-mailto) (attach-multiple-files lawlist-filename)))))
  

Мне нравится возможность удерживать dired-mark клавишу нажатой для повторения, но я бы хотел, чтобы она останавливалась на последней строке с файлом в буфере dired-mode. Любые идеи о том, как достичь этой цели, были бы высоко оценены. Перемещение мимо этой точки, выполнение теста, а затем возврат к предыдущей точке, по-видимому, не является очень эффективным средством обработки этого. Возможно, было бы лучше завершить буфер dired в конце последней строки файлом, чтобы не было пустой строки — т. Е., если в конце буфера режима dired нет пустой строки, то dired-mark туда нельзя перейти (так что это было бы хорошо?).


РЕДАКТИРОВАТЬ: сообщение отладчика было обновлено с полным обратным отслеживанием. Ниже приведена пользовательская функция, которая может быть, как предполагает @Drew, основной причиной сообщения об ошибке, которое я получаю:

 ;; E-mail attachments using Wanderlust.
(define-key dired-mode-map (kbd "C-c e") (lambda () (interactive)
  ;; if hovering over a directory, then do nothing
  (unless (file-directory-p (dired-get-file-for-visit))
    (let ((lawlist-filename
      (if (or (re-search-backward "^*" nil t)
              (re-search-forward "^*" nil t))
        (dired-get-marked-files)
        (dired-get-file-for-visit))))
    (wl-draft-mailto)
    (attach-multiple-files lawlist-filename)))))

(defun attach-multiple-files (amp;optional lawlist-filename)
"Either (dired-get-marked-files) or (dired-get-file-for-visit) when exiting recursive edit."
(interactive)
  (let* (
      new-dir
      (beg (point))
      (dir "/Users/HOME/.0.data"))
      (goto-char (point-min))
    (when (and (re-search-forward "username@hostname.com" nil t) (not (re-search-forward "username@hostname.comn" nil t)))
      (goto-char (point-max))
      (newline 2))
    (catch 'done
      (while t
        (goto-char (point-max))
        (let* (
          (multi-attach-variable t)
          (next-file
            (if lawlist-filename
              lawlist-filename
              (dired-read-file-name
                (if new-dir
                  new-dir
                  dir)))) )
          (setq new-dir
            (cond
              ((and next-file (stringp next-file))
                (file-name-directory next-file))
              ((and next-file (listp next-file))
                (file-name-directory (car next-file)))))
          (cond 
            ((stringp next-file)
              (mime-edit-insert-file next-file t))
            ((listp next-file)
              (mapcar (lambda (x) (mime-edit-insert-file x t)) next-file)))
          (setq lawlist-filename nil)
          (if (not (lawlist-y-or-n-p "Attach another? "))
                (progn
                  (goto-char beg)
                  (throw 'done nil))))))))
  

Комментарии:

1. 1. Откуда у вас это сообщение об ошибке? Я не вижу этого с emacs -Q или где-либо в dired-mark . dired-repeat-over-lines возвращает nil при перемещении в eob. Сообщение о том, что в строке без файла есть определенные действия. Чтобы избежать этого, проверьте, находится ли точка в строке с файлом. 2. Почему вы хотите остановиться перед eob — это просто для того, чтобы избежать сообщения об ошибке? (3. Не имеет прямого отношения, но может представлять интерес: с помощью клавиш Dired C-n , C-p , down и up оберните от конца / начала до начала / конца. Вы могли бы сделать аналогично для m , если хотите.)

2. @Drew — спасибо — я обновил вопрос с помощью пользовательской функции, которая может (как вы предположили) отвечать за ошибку (а не dired-mark ).). Нет особой причины останавливаться перед eob, за исключением того, чтобы избежать сообщения об ошибке. Время от времени мне нравится заглядывать в Dired в поисках отличных идей — я позаимствовал вашу необычную подсветку буфера dired-mode — это отличная библиотека.

3. @Drew — Спасибо, что помогли мне разобраться в проблеме. Пользовательская функция, которую я использовал, была одной из моих ранних попыток получить имена файлов в режиме dired. В других моих пользовательских библиотеках я уже переключился на метод, используемый dired-do-create-files . Итак, моя пользовательская функция, о которой идет речь в этом потоке, должна включать тот же метод. Я опубликовал ответ, который решит проблему. Как всегда, мы высоко ценим вашу помощь! Без вашей помощи я, вероятно, закончил бы тем, что попытался переписать что-то в режиме dired без необходимости.

Ответ №1:

Попробуйте defadvice включить dired-mark , чтобы избежать попадания на нейтральную полосу:

 (defadvice dired-mark (after stop-at-last-file activate)
  (when (eobp)
    (previous-line 1)))
  

Функция «двигаться вперед после пометки» встроена в dired-mark (на самом деле, если вы хотите разобраться в этом, в dired-repeat-over-lines ), поэтому этот совет проверяет, поместил ли он вас в эту пустую строку, и перемещает вас назад, если да. Ваш последний абзац предполагает, что вы, возможно, не очень заинтересованы в этой опции, но мне кажется, что это менее хлопотно, чем изменение внутренних элементов dired.

Комментарии:

1. Спасибо за идею — я подумаю об этом еще немного в контексте моей пользовательской функции и сообщу об этом.

Ответ №2:

Предыдущий ответ (17 октября 2014): Следующие 3 строки кода остановят функцию, если курсор не находится в файле или каталоге, и если ничего не было отмечено:

 (when (null (dired-get-marked-files))
  (let ((debug-on-quit nil))
    (signal 'quit `("You are not on a line containing a valid file or directory."))))
  

Пересмотренный ответ (20 января 2015 г.): Функция dired-insert-directory может быть изменена для удаления завершающих новых строк и / или пробелов в конце буфера следующим образом:

 (goto-char (point-max))
(let ((trailing-whitespace newlines (abs (skip-chars-backward "srnt"))))
  (when (> trailing-whitespace newlines 0)
    (delete-char trailing-whitespace newlines)))