Bagaimana saya bisa menyoroti garis duplikat?

8

Inilah yang saya miliki:

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

Tujuan saya adalah menambahkan ini untuk post-command-hookmenemukan baris tempat saya menduplikasi logika, tetapi ketika saya menjalankan perintah untuk kedua kalinya, itu tidak efektif (dan penguncian font lama masih berlaku).

Masalah kedua disebabkan oleh font-lock tidak menyegarkan sendiri. Saya sudah mencoba menambahkan (font-lock-mode -1) (font-lock-mode 1)definisi, tetapi itu tidak efektif.

Saya tidak tahu mengapa perintah itu hanya baik untuk sekali jalan.

Sean Allred
sumber
Coba balut bagian highlight-lines-matching-regexpdalamnya (let ((hi-lock-mode -1)) .. ). Saya melakukan itu untuk mengatasi masalah yang sama: github.com/kaushalmodi/.emacs.d/blob/…
Kaushal Modi
unhighlight-regexpbisa juga digunakan. Terlepas dari fitur ini mungkin paling baik diimplementasikan menggunakan fungsi pencocokan font-lock yang memindai buffer untuk garis duplikat dan menerapkan penyorotan pada mereka. Ini akan menangani unhighlighting secara otomatis setelah tidak ada garis duplikat.
Jordon Biondo
@kaushalmodi tidak beruntung :( terima kasih
Sean Allred
@JordonBiondo Saya memikirkan hal itu, tetapi highlight-lines-matching-regexpharus berlaku untuk kasus ini - hampir seperti sepatu. (Meskipun saya juga berpikir untuk menggunakan overlay, tapi itu konsep yang kurang saya kenal.)
Sean Allred
Anda bisa menyalin konten buffer ke buffer lain, lalu jalankan delete-duplicate-lines, lalu bedakan dua buffer.
wvxvw

Jawaban:

6
  1. Lihatlah font-lock-keywordssetelah Anda memanggil fungsi Anda. Anda akan melihat bahwa itu hanya memiliki regexp untuk baris pertama sebagai regexp untuk diklasifikasi. Yang Anda lakukan adalah mengambil garis yang diberikan dan meletakkan regexp untuk mencocokkannya font-lock-keywords- jadi hanya dups dari garis yang bisa disorot. TKI, regexp untuk baris pertama itu adalah hard-code font-lock-keywords.

  2. Sebagai gantinya, Anda bisa menggunakan FUNCTIONin font-lock-keywords. Tapi saya hanya akan mencari buffer untuk dups dari setiap baris, pada gilirannya, dan tidak repot dengan font-lock-keywords.

Inilah satu solusi cepat. Menggunakan fungsi hlt-highlight-regiondari Highlight Library ( highlight.el), tetapi Anda dapat menggunakan sesuatu yang lain jika Anda mau.

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

Dan ini adalah versi yang berfungsi pada (a) wilayah aktif atau (b) buffer penuh jika wilayah tidak aktif:

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

Dan jika Anda ingin wajah yang berbeda untuk setiap set dups kemudian hanya mengikat variabel facedi let, dan setqke (hlt-next-face)sebelah mana line-rediatur, dan ganti font-lock-warning-facedengan face. Opsi hlt-auto-face-backgroundsmengontrol wajah yang digunakan.

(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
sumber
Saya sebenarnya hanya mengerjakan sesuatu yang terlihat hampir sama persis, fungsi untuk fungsi! Satu hal yang saya sarankan adalah menghapus spasi spasi awal / akhir dari teks baris dan menambahkan sesuatu seperti [\ t] * ke awal dan akhir regexp sehingga baris pada level indent yang berbeda masih cocok.
Jordon Biondo
@JordonBiondo: Tapi bukan itu yang diminta OP. Apa pun mungkin, tetapi saya mengambil isyarat dari pertanyaan dan upaya pemecahannya: Dia tampaknya benar-benar ingin mencocokkan dengan tepat teks baris, dan mulai dari bol, yaitu, tidak mengabaikan lekukan atau jejak spasi putih. Tapi ya, banyak varian yang memungkinkan. Entah betapa berguna hal seperti ini sebenarnya. Saya kira itu tergantung pada apa yang ingin Anda lakukan dengannya.
Drew
Yah, kasus penggunaan saya adalah untuk mengenali di mana logika digandakan sehingga saya dapat mencoba untuk mengoptimalkan :) Saya membuat sketsa algoritma dan menggunakan sintaks formal, jadi duplikat yang tepat lebih dari mungkin.
Sean Allred
Tidak yakin apa maksudmu, Sean. Tetapi jika Anda ingin mengabaikan whitespace memimpin dan mengikuti, seperti yang disarankan @JordonBiondo, maka lakukan saja seperti yang ia sarankan: tambahkan awalan spasi-spasi yang mungkin dan sufiks ke regexp.
Drew
Saya mencoba menggunakan fungsi terakhir Anda tetapi ketika mengkompilasi definisi fungsi saya dapatkan setq: Symbol's value as variable is void: hlt-highlight-line-dups-ignore-regexp. Bagaimana variabel ini didefinisikan?
Patrick
1

Bagaimana kalau menggunakan overlay alih-alih 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) '<))))))

Buat wilayah, lalu M-x my-highlight-duplicate-lines-in-region Anda dapat menghapus semua overlay denganM-x ov-clear

Shingo Fukuyama
sumber
0

Ini agak samar, tetapi dengan sedikit usaha (lihat C-h fediff-buffersRETinfo tentang HOOKargumennya) Anda bisa membuatnya tampil lebih baik / melakukan pembersihan yang lebih baik setelah keluar dari 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
sumber
0

Peningkatan jawaban di atas oleh Shingo Fukuyama.

Versi ini memeriksa duplikat baris di wilayah aktif tetapi jika tidak ada, cari seluruh 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) '<)))))
Sawan
sumber