Come posso evidenziare le linee duplicate?


8

Ecco cosa ho:

(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))

La mia intenzione è quella di aggiungere questo per post-command-hooktrovare le linee in cui sto duplicando la logica, ma quando eseguo il comando una seconda volta, è inefficace (e il vecchio blocco dei caratteri è ancora attivo).

Il secondo problema è causato dal blocco dei caratteri che non si aggiorna da solo. Ho provato ad aggiungere (font-lock-mode -1) (font-lock-mode 1)a alla definizione, ma era inefficace.

Non ho idea del perché il comando sarebbe buono solo per una corsa, però.


Prova a avvolgere l' highlight-lines-matching-regexpinterno (let ((hi-lock-mode -1)) .. ). L'ho fatto per risolvere lo stesso problema: github.com/kaushalmodi/.emacs.d/blob/…
Kaushal Modi,

unhighlight-regexppuò anche essere usato. Indipendentemente da ciò, questa funzione è probabilmente meglio implementata usando una funzione di corrispondenza del blocco dei caratteri che scansiona il buffer alla ricerca di linee duplicate e applica l'evidenziazione ad esse. Ciò gestirà automaticamente la non evidenziazione quando non ci sono linee duplicate.
Jordon Biondo,

@kaushalmodi nessuna tale fortuna :( grazie però
Sean Allred l'

@JordonBiondo Ci ho pensato, ma highlight-lines-matching-regexpdeve essere applicabile a questo caso: è quasi una scarpa. (Anche se ho pensato anche di usare le sovrapposizioni, ma è un concetto con cui ho meno familiarità.)
Sean Allred,

È possibile copiare il contenuto del buffer in un altro buffer, quindi eseguirlo delete-duplicate-lines, quindi diff due buffer.
wvxvw,

Risposte:


6
  1. Dai un'occhiata font-lock-keywordsdopo aver chiamato la tua funzione. Vedrai che ha solo il regexp per la prima riga come regexp da fontiificare. Tutto quello che hai fatto è stato prendere una determinata linea e inserire una regexp per abbinarla, font-lock-keywordsquindi vengono evidenziati solo i duplicati di quella linea. IOW, il regexp per quella prima riga è codificato font-lock-keywords.

  2. Invece, potresti usare un FUNCTIONin font-lock-keywords. Ma vorrei solo cercare nel buffer i duplicati di ogni riga, a sua volta, senza preoccuparmi font-lock-keywords.

Ecco una soluzione rapida. Utilizza la funzione hlt-highlight-regiondella libreria Highlight ( highlight.el), ma puoi usare qualcos'altro se vuoi.

(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)))))

Ed ecco una versione che funziona su (a) la regione attiva o (b) il buffer completo se la regione non è attiva:

(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)))))

E se si desidera una faccia diversa per ogni insieme di dups poi basta associare una variabile facenel let, e setqal (hlt-next-face)vicino a dove line-reè impostato, e sostituire font-lock-warning-facecon face. L'opzione hlt-auto-face-backgroundscontrolla i volti utilizzati.

(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)))))

In realtà stavo solo lavorando su qualcosa che sembra quasi identico, funzione per funzione! Una cosa che suggerirei è di rimuovere lo spazio bianco iniziale / finale dal testo della riga e aggiungere qualcosa come [\ t] * all'inizio e alla fine della regexp in modo che le linee a diversi livelli di rientro corrispondano ancora.
Jordon Biondo,

@JordonBiondo: Ma non è quello che l'OP ha richiesto. Tutto è possibile, ma ho preso spunto dalla domanda e dal tentativo di soluzione: apparentemente vuole davvero abbinare esattamente il testo della riga e iniziare da bol, cioè non trascurare il rientro o lo spazio bianco finale. Sì, sono possibili molte varianti. Non so quanto sia utile qualcosa di simile. Immagino che dipenda da cosa vuoi farci.
Estratto l'

Bene, il mio caso d'uso è riconoscere dove viene duplicata la logica in modo che io possa provare a ottimizzare :) Sto disegnando un algoritmo e usando una sintassi formale, quindi i duplicati esatti sono più che possibili.
Sean Allred,

Non sono sicuro di cosa intendi, Sean. Ma se vuoi ignorare gli spazi bianchi iniziali e finali, come suggerito da @JordonBiondo, fai semplicemente come suggerito: aggiungi un prefisso possibile-spazio bianco e suffisso al regexp.
Estratto l'

Ho provato a usare la tua ultima funzione ma quando compilo la definizione della funzione ottengo setq: Symbol's value as variable is void: hlt-highlight-line-dups-ignore-regexp. Come viene definita questa variabile?
Patrick,

1

Che ne dici di usare overlay invece di font-lock?

;; 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) '<))))))

Crea regione, quindi M-x my-highlight-duplicate-lines-in-region puoi cancellare tutti gli overlay diM-x ov-clear


0

Questo è un po 'impreciso, ma con un certo sforzo (vedi C-h fediff-buffersRETper le informazioni HOOKsull'argomento) potresti renderlo migliore / eseguire una pulizia migliore all'uscita dalla modalità 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))))

0

Miglioramento della risposta sopra di Shingo Fukuyama.

Questa versione verifica la presenza di righe duplicate nell'area attiva ma, se non ce ne sono, cerca l'intero buffer.

(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) '<)))))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.