¿Cómo puedo resaltar líneas duplicadas?


8

Esto es lo que tengo:

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

Mi intención es agregar esto para post-command-hookencontrar líneas donde estoy duplicando la lógica, pero cuando ejecuto el comando por segunda vez, es ineficaz (y el bloqueo de fuente antiguo todavía está en vigor).

El segundo problema es causado por el bloqueo de fuente que no se actualiza. Intenté agregar un (font-lock-mode -1) (font-lock-mode 1)a la definición, pero fue ineficaz.

Sin embargo, no tengo idea de por qué el comando solo sería bueno para una ejecución.


Intenta envolver el highlight-lines-matching-regexpinterior (let ((hi-lock-mode -1)) .. ). Lo hice para resolver el mismo problema: github.com/kaushalmodi/.emacs.d/blob/…
Kaushal Modi

unhighlight-regexptambién puede ser usado. Independientemente de que esta característica probablemente se implemente mejor utilizando una función de coincidencia de bloqueo de fuente que escanea el búfer en busca de líneas duplicadas y les aplica resaltado. Esto manejaría la falta de resaltado automáticamente una vez que no haya líneas duplicadas.
Jordon Biondo

@kaushalmodi no tal suerte :( aunque gracias
Sean Allred

@JordonBiondo Pensé en eso, pero highlight-lines-matching-regexpdebe ser aplicable a este caso, es casi un zapato. (Aunque también pensé en usar superposiciones, pero ese es un concepto con el que estoy menos familiarizado)
Sean Allred

Puede copiar el contenido del búfer en otro búfer, luego ejecutar delete-duplicate-lines, luego diferir dos búferes.
wvxvw

Respuestas:


6
  1. Eche un vistazo font-lock-keywordsdespués de haber llamado a su función. Verá que solo tiene la expresión regular para la primera línea como la expresión regular para fontify. Todo lo que hizo fue tomar una línea determinada y poner una font-lock-keywordsexpresión regular para que coincida con ella , por lo que solo se resaltan los duplicados de esa línea. IOW, la expresión regular para esa primera línea está codificada font-lock-keywords.

  2. En su lugar, se puede usar una FUNCTIONen font-lock-keywords. Pero solo buscaría en el búfer duplicados de cada línea, a su vez, y no me molestaría font-lock-keywords.

Aquí hay una solución rápida. Utiliza la función hlt-highlight-regionde la biblioteca Highlight ( highlight.el), pero puede usar algo más si lo desea.

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

Y aquí hay una versión que funciona en (a) la región activa o (b) el búfer completo si la región no está activa:

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

Y si desea una cara diferente para cada conjunto de dups , simplemente vincule una variable faceen el let, y setqal (hlt-next-face)lado de donde line-rese establece, y reemplace font-lock-warning-facecon face. La opción hlt-auto-face-backgroundscontrola las caras utilizadas.

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

En realidad solo estaba trabajando en algo que se ve casi exactamente igual, ¡función por función! Una cosa que sugeriría es eliminar el espacio en blanco inicial / final del texto de la línea y agregar algo como [\ t] * al principio y al final de la expresión regular para que las líneas en diferentes niveles de sangría sigan coincidiendo.
Jordon Biondo

@JordonBiondo: Pero eso no es lo que pidió el OP. Cualquier cosa es posible, pero tomé el ejemplo de la pregunta y el intento de solución: aparentemente, realmente quiere coincidir exactamente con el texto de la línea y comenzar en bol, es decir, sin ignorar la sangría o el espacio en blanco al final. Pero sí, hay muchas variantes posibles. No sé cuán útil es realmente algo como esto. Supongo que depende de lo que quieras hacer con él.
Dibujó

Bueno, mi caso de uso es reconocer dónde se duplica la lógica para poder intentar optimizar :) Estoy esbozando un algoritmo y usando una sintaxis formal, por lo que los duplicados exactos son más que posibles.
Sean Allred

No estoy seguro de lo que quieres decir, Sean. Pero si desea ignorar los espacios en blanco iniciales y finales, como sugirió @JordonBiondo, simplemente haga lo que sugirió: agregue un prefijo y sufijo de espacios en blanco posibles a la expresión regular.
Dibujó

Intenté usar su última función, pero al compilar la definición de la función que obtengo setq: Symbol's value as variable is void: hlt-highlight-line-dups-ignore-regexp. ¿Cómo se define esta variable?
Patrick

1

¿Qué tal usar overlay en lugar de 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) '<))))))

Haga una región y luego M-x my-highlight-duplicate-lines-in-region puede borrar todas las superposicionesM-x ov-clear


0

Esto es un poco incompleto, pero con algo de esfuerzo (vea C-h fediff-buffersRETla información sobre el HOOKargumento) podría hacer que se muestre mejor / realizar una limpieza mejor al salir del modo 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

Mejora en la respuesta anterior por Shingo Fukuyama.

Esta versión busca líneas duplicadas en la región activa, pero si no hay ninguna, busca en todo el búfer.

(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) '<)))))
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.