Wie kann ich doppelte Zeilen hervorheben?

8

Folgendes habe ich:

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

Ich möchte dies hinzufügen post-command-hook, um Zeilen zu finden, in denen ich Logik dupliziere. Wenn ich den Befehl jedoch ein zweites Mal ausführe, ist er unwirksam (und die alte Schriftsperrung ist immer noch wirksam).

Das zweite Problem wird dadurch verursacht, dass sich die Schriftsperre nicht selbst aktualisiert. Ich habe versucht (font-lock-mode -1) (font-lock-mode 1), der Definition ein hinzuzufügen , aber es war unwirksam.

Ich habe jedoch keine Ahnung, warum der Befehl nur für einen Lauf gut wäre.

Sean Allred
quelle
Versuchen Sie, das highlight-lines-matching-regexpInnere einzuwickeln (let ((hi-lock-mode -1)) .. ). Ich habe das getan, um das gleiche Problem zu lösen: github.com/kaushalmodi/.emacs.d/blob/…
Kaushal Modi
unhighlight-regexpkann auch benutzt werden. Unabhängig davon lässt sich diese Funktion wahrscheinlich am besten mit einer Funktion zum Abgleichen der Schriftsperre implementieren, die den Puffer nach doppelten Zeilen durchsucht und diese hervorhebt. Dies würde die Hervorhebung automatisch behandeln, sobald keine doppelten Zeilen vorhanden sind.
Jordon Biondo
@ Kaushalmodi kein solches Glück :( Danke aber
Sean Allred
@JordonBiondo Ich habe darüber nachgedacht, highlight-lines-matching-regexpmuss aber auf diesen Fall anwendbar sein - es ist fast ein Schuh-in. (Obwohl ich auch über die Verwendung von Overlays nachgedacht habe, ist mir dieses Konzept weniger vertraut.)
Sean Allred
Sie können den Inhalt des Puffers in einen anderen Puffer kopieren, dann ausführen delete-duplicate-linesund dann zwei Puffer unterscheiden.
wvxvw

Antworten:

6
  1. Schauen Sie sich an, font-lock-keywordsnachdem Sie Ihre Funktion aufgerufen haben. Sie werden sehen, dass es nur den regulären Ausdruck für die erste Zeile als regulären Ausdruck für die Schriftart gibt. Alles, was Sie getan haben, war, eine bestimmte Zeile aufzunehmen und einen passenden regulären Ausdruck einzufügen font-lock-keywords- damit nur Dups dieser Zeile hervorgehoben werden. IOW, der reguläre Ausdruck für diese erste Zeile ist fest codiert font-lock-keywords.

  2. Stattdessen können Sie ein FUNCTIONin verwenden font-lock-keywords. Aber ich würde einfach den Puffer nacheinander nach Dups jeder Zeile durchsuchen und mich nicht darum kümmern font-lock-keywords.

Hier ist eine schnelle Lösung. Es verwendet die Funktion hlt-highlight-regionaus der Highlight- Bibliothek ( highlight.el), aber Sie können auch etwas anderes verwenden, wenn Sie möchten.

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

Und hier ist eine Version, die auf (a) der aktiven Region oder (b) dem vollen Puffer funktioniert, wenn die Region nicht aktiv ist:

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

Und wenn Sie für jede Gruppe von Dups ein anderes Gesicht möchten, binden Sie einfach eine Variable facein die letund setqan die Stelle (hlt-next-face), an der sie festgelegt line-reist, und ersetzen Sie sie font-lock-warning-facedurch face. Option hlt-auto-face-backgroundssteuert die verwendeten Gesichter.

(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)))))
Drew
quelle
Ich habe gerade an etwas gearbeitet, das fast genau gleich aussieht, Funktion für Funktion! Eine Sache, die ich vorschlagen würde, ist, das führende / nachfolgende Leerzeichen aus dem Text der Zeile zu entfernen und am Anfang und Ende des regulären Ausdrucks etwas wie [\ t] * hinzuzufügen, damit Zeilen mit unterschiedlichen Einrückungsstufen immer noch übereinstimmen.
Jordon Biondo
@JordonBiondo: Aber das hat das OP nicht verlangt. Alles ist möglich, aber ich habe mich an der Frage und dem Lösungsversuch orientiert: Er möchte anscheinend wirklich genau mit dem Zeilentext übereinstimmen und bei bol beginnen, dh Einrückungen oder nachgestellte Leerzeichen nicht außer Acht lassen. Aber ja, viele Varianten sind möglich. Keine Ahnung, wie nützlich so etwas wirklich ist. Ich denke, es hängt davon ab, was Sie damit machen wollen.
Drew
Mein Anwendungsfall besteht darin, zu erkennen, wo Logik dupliziert wird, damit ich versuchen kann, sie zu optimieren :) Ich skizziere einen Algorithmus und verwende eine formale Syntax, sodass exakte Duplikate mehr als möglich sind.
Sean Allred
Ich bin mir nicht sicher, was du meinst, Sean. Wenn Sie jedoch führende und nachfolgende Leerzeichen ignorieren möchten, wie von @JordonBiondo vorgeschlagen, tun Sie einfach das, was er vorgeschlagen hat: Fügen Sie dem regulären Ausdruck ein Präfix und ein Suffix für mögliche Leerzeichen hinzu.
Drew
Ich habe versucht, Ihre letzte Funktion zu verwenden, aber beim Kompilieren der Funktionsdefinition erhalte ich setq: Symbol's value as variable is void: hlt-highlight-line-dups-ignore-regexp. Wie ist diese Variable definiert?
Patrick
1

Wie wäre es mit Overlay anstelle von 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) '<))))))

Region erstellen, und dann können M-x my-highlight-duplicate-lines-in-region Sie alle Überlagerungen durch löschenM-x ov-clear

Shingo Fukuyama
quelle
0

Dies ist etwas lückenhaft, aber mit etwas Aufwand (siehe C-h fediff-buffersRETInformationen zum HOOKArgument) können Sie die Anzeige verbessern / eine bessere Bereinigung durchführen, wenn Sie den Diff-Modus verlassen:

(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
quelle
0

Verbesserung der obigen Antwort von Shingo Fukuyama.

Diese Version sucht im aktiven Bereich nach doppelten Zeilen. Wenn jedoch keine vorhanden sind, wird der gesamte Puffer durchsucht.

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