Comment mettre en évidence des lignes en double?

8

Voici ce que j'ai:

(defun my-show-duplicate-lines ()
  (interactive)
  (highlight-lines-matching-regexp
   (concat "^"
           (regexp-quote
            (substring-no-properties
             (thing-at-point 'line) 0 -1))
           "$")
   font-lock-warning-face))

Mon intention est d'ajouter ceci pour post-command-hooktrouver des lignes où je duplique la logique, mais lorsque j'exécute la commande une deuxième fois, c'est inefficace (et l'ancien verrouillage de police est toujours en vigueur).

Le deuxième problème est dû au fait que le verrouillage des polices ne se rafraîchit pas. J'ai essayé d'ajouter un (font-lock-mode -1) (font-lock-mode 1)à la définition, mais c'était inefficace.

Je n'ai aucune idée de la raison pour laquelle la commande ne serait valable que pour une seule exécution, cependant.

Sean Allred
la source
Essayez d'envelopper l' highlight-lines-matching-regexpintérieur (let ((hi-lock-mode -1)) .. ). J'ai fait ça pour résoudre le même problème: github.com/kaushalmodi/.emacs.d/blob/…
Kaushal Modi
unhighlight-regexppeut également être utilisé. Quoi qu'il en soit, cette fonctionnalité est probablement mieux implémentée à l'aide d'une fonction de correspondance de verrouillage de police qui analyse le tampon pour les lignes en double et leur applique une surbrillance. Cela gérerait la mise en surbrillance automatiquement une fois qu'il n'y a pas de lignes en double.
Jordon Biondo
@kaushalmodi pas de chance :( merci quand même
Sean Allred
@JordonBiondo J'y ai pensé, mais cela highlight-lines-matching-regexpdoit être applicable à ce cas - c'est presque une chaussure. (Bien que j'aie également pensé à utiliser des superpositions, mais c'est un concept que je connais moins bien.)
Sean Allred
Vous pouvez copier le contenu du tampon dans un autre tampon, puis l'exécuter delete-duplicate-lines, puis différencier deux tampons.
wvxvw

Réponses:

6
  1. Jetez un œil font-lock-keywordsaprès avoir appelé votre fonction. Vous verrez qu'il a juste l'expression rationnelle pour la première ligne comme expression rationnelle à polices. Tout ce que vous avez fait était de choisir une ligne donnée et de mettre une expression rationnelle pour la faire correspondre font-lock-keywords- donc seuls les doublons de cette ligne sont mis en évidence. IOW, l'expression rationnelle de cette première ligne est codée en dur font-lock-keywords.

  2. Au lieu de cela, vous pouvez utiliser un FUNCTIONin font-lock-keywords. Mais je voudrais simplement rechercher dans le tampon des doublons de chaque ligne, à mon tour, et ne pas m'embêter avec font-lock-keywords.

Voici une solution rapide. Il utilise la fonction hlt-highlight-regionde la bibliothèque Highlight ( highlight.el), mais vous pouvez utiliser autre chose si vous le souhaitez.

(defun highlight-line-dups ()
  (interactive)
  (let ((count  0)
        line-re)
    (save-excursion
      (goto-char (point-min))
      (while (not (eobp))
        (setq count    0
              line-re  (concat "^" (regexp-quote (buffer-substring-no-properties
                                                  (line-beginning-position)
                                                  (line-end-position)))
                               "$"))
        (save-excursion
          (goto-char (point-min))
          (while (not (eobp))
            (if (not (re-search-forward line-re nil t))
                (goto-char (point-max))
              (setq count  (1+ count))
              (unless (< count 2)
                (hlt-highlight-region (line-beginning-position) (line-end-position)
                                      'font-lock-warning-face)
                (forward-line 1)))))
        (forward-line 1)))))

Et voici une version qui fonctionne sur (a) la région active ou (b) le tampon complet si la région n'est pas active:

(defun highlight-line-dups-region (&optional start end face msgp)
  (interactive `(,@(hlt-region-or-buffer-limits) nil t))
  (let ((count  0)
        line-re)
    (save-excursion
      (goto-char start)
      (while (< (point) end)
        (setq count    0
              line-re  (concat "^" (regexp-quote (buffer-substring-no-properties
                                                  (line-beginning-position)
                                                  (line-end-position)))
                               "$"))
        (save-excursion
          (goto-char start)
          (while (< (point) end)
            (if (not (re-search-forward line-re nil t))
                (goto-char end)
              (setq count  (1+ count))
              (unless (< count 2)
                (hlt-highlight-region
                 (line-beginning-position) (line-end-position)
                 face)
                (forward-line 1)))))
        (forward-line 1)))))

Et si vous voulez un visage différent pour chaque ensemble de doublons, liez simplement une variable facedans le let, et setqà (hlt-next-face)côté de l'endroit où line-reest défini, et remplacez-le font-lock-warning-facepar face. L'option hlt-auto-face-backgroundscontrôle les faces utilisées.

(defun hlt-highlight-line-dups-region (&optional start end msgp)
  (interactive `(,@(hlt-region-or-buffer-limits) t))
  (let ((hlt-auto-faces-flag  t)
        count line line-re ignore-re)
    (save-excursion
      (goto-char start)
      (while (< (point) end)
        (setq count    0
              line     (buffer-substring-no-properties (line-beginning-position)
                                                       (line-end-position))
              ignore   (and (not (string= "" line))  "[ \t]*")
              line-re  (concat "^" ignore (regexp-quote line) ignore "$"))
        (save-excursion
          (goto-char start)
          (while (< (point) end)
            (if (not (re-search-forward line-re end t))
                (goto-char end)
              (setq count  (1+ count))
              (unless (< count 2)
                (hlt-highlight-region (line-beginning-position) (line-end-position))
                (forward-line 1)))))
        (forward-line 1)))))
A dessiné
la source
En fait, je travaillais sur quelque chose qui ressemble presque exactement, fonction pour fonction! Une chose que je suggérerais serait de supprimer les espaces de début / fin du texte de la ligne et d'ajouter quelque chose comme [\ t] * au début et à la fin de l'expression régulière afin que les lignes à différents niveaux de retrait correspondent toujours.
Jordon Biondo
@JordonBiondo: Mais ce n'est pas ce que le PO a demandé. Tout est possible, mais je me suis inspiré de la question et de la tentative de solution: il veut apparemment vraiment correspondre exactement au texte de la ligne et commencer par bol, c'est-à-dire ne pas négliger l'indentation ou les espaces en fin. Mais oui, beaucoup de variantes sont possibles. Ne sais pas à quel point quelque chose comme ça est vraiment utile. Je suppose que cela dépend de ce que vous voulez en faire.
Drew
Eh bien, mon cas d'utilisation est de reconnaître où la logique est dupliquée afin que je puisse essayer d'optimiser :) J'esquisse un algorithme et j'utilise une syntaxe formelle, donc les doublons exacts sont plus que possibles.
Sean Allred
Je ne sais pas ce que tu veux dire, Sean. Mais si vous voulez ignorer les espaces blancs de début et de fin, comme l'a suggéré @JordonBiondo, faites simplement ce qu'il a suggéré: ajoutez un préfixe et un suffixe d'espace blanc possibles à l'expression rationnelle.
Drew
J'ai essayé d'utiliser votre dernière fonction mais lors de la compilation de la définition de fonction que j'obtiens setq: Symbol's value as variable is void: hlt-highlight-line-dups-ignore-regexp. Comment cette variable est-elle définie?
Patrick
1

Que diriez-vous d'utiliser la superposition au lieu du verrouillage de police?

;; https://github.com/ShingoFukuyama/ov.el
(require 'ov)

(defun my-highlight-duplicate-lines-in-region ()
  (interactive)
  (if mark-active
      (let* (($beg (region-beginning))
             ($end (region-end))
             ($st (buffer-substring-no-properties
                   $beg $end))
             ($lines)
             $dup)
        (deactivate-mark t)
        (save-excursion
          (goto-char $beg)
          (while (< (point) $end)
            (let* (($b (point))
                   ($e (point-at-eol))
                   ($c (buffer-substring-no-properties $b $e))
                   ($a (assoc $c $lines)))
              (when (not (eq $b $e))
                (if $a
                    (progn
                      (setq $dup (cons $b $dup))
                      (setq $dup (cons (cdr $a) $dup)))
                  (setq $lines
                        (cons (cons $c $b) $lines)))))
            (forward-line 1))
          (mapc (lambda ($p)
                  (ov-set (ov-line $p) 'face '(:foreground "red")))
                (sort (delete-dups $dup) '<))))))

Créer une région, puis M-x my-highlight-duplicate-lines-in-region vous pouvez effacer toutes les superpositions enM-x ov-clear

Shingo Fukuyama
la source
0

C'est un peu sommaire, mais avec un peu d'effort (voir C-h fediff-buffersRETpour les informations sur l' HOOKargument), vous pourriez le faire afficher mieux / effectuer un meilleur nettoyage en quittant le mode diff:

(defun my/show-duplicate-lines (beg end)
  (interactive "r")
  (unless (region-active-p)
    (setf beg (point-min)
          end (point-max)))
  (let ((copy (buffer-substring beg end))
        (original (current-buffer))
        (dupes-buffer (get-buffer-create (format "%s[dupes]" (buffer-name)))))
    (with-current-buffer dupes-buffer
      (erase-buffer)
      (insert copy)
      (delete-duplicate-lines (point-min) (point-max))
      (ediff-buffers original dupes-buffer))))
wvxvw
la source
0

Amélioration de la réponse ci-dessus par Shingo Fukuyama.

Cette version vérifie les lignes en double dans la région active mais s'il n'y en a pas, recherche tout le tampon.

(require 'ov)
(defun highlight-duplicate-lines-in-region-or-buffer ()
(interactive)

  (let* (
    ($beg (if mark-active (region-beginning) (point-min)))
    ($end (if mark-active (region-end) (point-max)))
    ($st (buffer-substring-no-properties $beg $end))
    ($lines)
    ($dup))
  (deactivate-mark t)
  (save-excursion
    (goto-char $beg)
    (while (< (point) $end)
      (let* (($b (point))
         ($e (point-at-eol))
         ($c (buffer-substring-no-properties $b $e))
         ($a (assoc $c $lines)))
    (when (not (eq $b $e))
      (if $a
          (progn
        (setq $dup (cons $b $dup))
        (setq $dup (cons (cdr $a) $dup)))
        (setq $lines
          (cons (cons $c $b) $lines)))))
      (forward-line 1))
    (mapc (lambda ($p)
        (ov-set (ov-line $p) 'face '(:foreground "red")))
      (sort (delete-dups $dup) '<)))))
Sawan
la source