le paragraphe de remplissage marque le fichier comme modifié, même s'il n'a rien fait

11

Chaque fois que j'appelle fill-paragraph, le tampon est toujours marqué comme modifié, même si la commande n'a eu aucun effet (c'est-à-dire si le paragraphe était déjà rempli). Il crée également une action annulable vide (facilement détectable avec undo-tree-mode). D'autres commandes susceptibles d'apporter des modifications, telles que les commandes d'indentation, ne marquent pas le tampon comme modifié ou ne créent pas d'action à annuler si rien n'a été modifié. Existe-t-il un moyen de fill-paragraphmarquer le tampon modifié et de créer une action annulable uniquement s'il a réellement changé quelque chose?

Lily Chung
la source
Je ne pense pas que ce soit correct - M-qne marque pas le tampon modifié par défaut, du moins d'après mes tests. Quel mode utilisez-vous? Je suppose que le mode écrase fill-paragraphd'une certaine manière.
shosti
@shosti J'utilise le mode fondamental. Le paragraphe doit comporter plusieurs lignes (lorsqu'il est correctement rempli).
Lily Chung
Ah OK je le vois maintenant.
shosti

Réponses:

2

Notez que cela est corrigé pour les nouveaux Emacsen (v.26 vers le haut).

clemera
la source
10

Le problème est que fill-paragraph(ou plutôt, fill-region-as-paragraph) supprimera et réinsérera les nouvelles lignes pendant qu'il décompose votre paragraphe. Il ne modifiera pas le tampon s'il n'y a qu'une seule ligne. Le no-op dans la liste d'annulation dont vous êtes témoin fill-paragraphsupprime et réinsère simplement les nouvelles lignes.

Il n'est pas trivial d'éviter cela. Ce qui suit est un très mauvais hack, et très inefficace pour les gros tampons, mais peut-être que cela fonctionne pour vous. La commande imite fill-paragraph( M-q) avec le comportement identique, sauf qu'elle stocke le contenu du tampon avant de l'appeler, et ensuite, si le contenu est resté le même, elle restaurera l'état de modification et annulera la liste d'avant la modification. Pour ce faire, il a besoin d'une copie (deux, en fait) du contenu du tampon, donc vraiment, c'est assez inefficace. :-)

(defun my/fill-paragraph (&optional justify region)
  (interactive (progn
                 (barf-if-buffer-read-only)
                 (list (if current-prefix-arg 'full) t)))
  (let ((old-text (buffer-string))
        (old-modified (buffer-modified-p))
        (old-undo-list buffer-undo-list))
    (fill-paragraph justify region)
    (when (equal old-text (buffer-string))
      (setq buffer-undo-list old-undo-list)
      (set-buffer-modified-p old-modified))))

Vous pouvez lier cela à M-q.

Jorgen Schäfer
la source
1
Oui, cela a longtemps été une douleur. ;-) Je me demande (je ne me souviens pas) si un correctif a été demandé auparavant. On dirait que ça l'aurait été.
Drew
Hmmm. Je me demande s'il y a une meilleure solution qui n'a pas à vérifier la totalité du tampon - peut-être pourrait-il vérifier uniquement le paragraphe sélectionné?
Lily Chung
fill-paragraphfait une distinction entre divers cas, c'est-à-dire se comporte différemment selon une région active, les fonctions de paragraphe de remplissage existantes, etc. Vous devez reproduire ce comportement pour déterminer quelles parties du tampon vont réellement être modifiées. Possible, mais délicat. :-)
Jorgen Schäfer
@Drew Il y a eu une longue discussion à ce sujet sur la liste de diffusion l'année dernière: bug # 13949: 24.3.50; 'fill-paragraph' ne devrait pas toujours mettre le tampon tel que modifié
dkim
@dkim: Oui, je m'en souviens maintenant. Et rien n'en est jamais sorti ...
Drew
1

Réponse tardive, mais voici une version simple qui ne modifie pas le tampon si le texte ne change pas.

(defun my-fill-paragraph (&optional justify region)
  "Fill paragraph, but don't modify the buffer if filling doesn't
change the text.  See `fill-paragraph' for details."
  (interactive (progn
                 (barf-if-buffer-read-only)
                 (list (if current-prefix-arg 'full) t)))
  (if (buffer-modified-p)
      ;; if modified: use standard fill-paragraph
      (fill-paragraph justify region)
    ;; if unmodified: get a candidate filled version
    (save-excursion
      (let* ((col fill-column)
             (beg (progn (forward-paragraph -1)
                         (skip-syntax-forward " >")
                         (point)))
             (end (progn (forward-paragraph 1)
                         (skip-syntax-backward " >")
                         (point)))
             (old (buffer-substring-no-properties beg end))
             (new (with-temp-buffer
                    (setq fill-column col)
                    (insert old)
                    (fill-paragraph justify region)
                    (buffer-string))))
        ;; don't modify unless the old and new versions differ
        (unless (string-equal old new)
          (delete-region beg end)
          (insert new))))))

Il adapte certaines des idées de la réponse de @ JorgenSchäfer, mais ne fonctionne qu'avec le paragraphe actuel, et uniquement de manière simple, séparée par des espaces (voir les commentaires sur la réponse de @ JorgenSchäfer sur les complications sous le capot).

Il s'agit du seul cas d'utilisation pertinent pour mes propres besoins (c'est-à-dire une utilisation interactive avec une prose "normale", pas de région active), donc je le poste au cas où quelqu'un voudrait l'utiliser ou l'améliorer pour des cas d'utilisation plus compliqués. .

Dan
la source