Як рекурсивно шукати / grep вміст файлів у каталозі / підкаталогах у Emacs?


14

Я використовую Emacs досить довгий час, і я все ще якимось чином не розумію, який найкращий спосіб (рекурсивно) схопити рядок у каталозі (project) і отримати результати, представлені або як переповнений буфер, або в деяких навіть більше корисний спосіб. Будь ласка, просвіти мене.


Ви спробували скористатися helm-projectile-grepкомандою (якщо у вас встановлений кермовий снаряд) або projectile-grep?
Чакраварті Рагунандан

Я не знаю , що helmі projectileє, але якщо це рекомендований засіб, я б встановити і вивчити його.
Борис Стітнікі

Так, снаряд - це пакет, який забезпечує простий спосіб виконати те, що ви згадали у питанні, командою projectile-grep. Також я настійно рекомендую встановити helmпакет. Я не уявляю, як запускати emacs без helmі helm-projectile. Можливо, вам також буде цікавий helm-agпакет (який забезпечує інтерфейс керма для пошуку срібла в Emacs, який, мабуть, швидше, ніж grep або ack).
Чакраварті Рагунандан

2
Щоб питання було більш корисним та легшим для пошуку майбутніх шукачів Google та форуму, можливо, подумайте про зміну заголовка питання, щоб воно включало рекурсивно слово , і розглянути можливість обмеження сфери застосування - наприклад, як рекурсивно збирати вміст файлів у каталозі / підкаталоги . Це лише приклад - натомість це може бути щось інше.
законник

1
Хоча поки що в коментарях та відповідях запропоновано ряд пакетів, щоб зробити це різними фантазійними способами, я не бачу з вашого запитання, чому прості M-x grepне роблять те, що вам потрібно. Давайте ви дасте довільний командний рядок, я іноді використовую findтам, коли мені потрібна рекурсія.
КАРТА

Відповіді:


15

Ну, оскільки оригінальне запитання не згадується rgrep, я продовжу тут і вказую його. Це найпростіший варіант, вже вбудований в Emacs, і я виявив, що його більш ніж достатньо для більшості речей.

З документації,

Recursively grep for REGEXP in FILES in directory tree rooted at DIR.

Пошук обмежується іменами файлів, що відповідають шаблону оболонки FILES.

Так, наприклад, щоб знайти всі файли пітона під моїй домашній директорії для використання some_function, я б назвав його some_function, *.py, в ~/якості аргументів. Результати відображаються в новому буфері.


1
Можливо, хотілося б згадати find-grep-diredтакож, оскільки згадується в ОП "результати, представлені або як переповнений буфер, або ..."
npostavs

@npostavs Я ще не використовував find-grep-diredсебе, не соромтесь додати це у відповідь.
користувач2699

Одного разу я експериментував із подібними ак-аґ та на припущенні, що я повинен переходити з rgrep на щось, використовуючи ці, оскільки вони повинні були бути кращими. Врешті-решт я залишився з rgrep, тому що не знайшов користі для зміни! У командному рядку, безумовно, має бути зроблений випадок, але в Emacs rgrepробиться настільки хороша робота з націлювання на пошук, що між ними не було суттєвих різниць швидкості. (Я хочу сказати, що rgrep у деяких випадках був частково швидшим , але я не пам’ятаю точно.)
phils

1
Зауважте, що next-errorі previous-errorможе використовуватися для навігації по набору результатів. Я знаходжу M-g M-nі M-g M-pнайзручніші із стандартних палітур.
філс

find-grep-diredне дає мені буфера з перехресними посиланнями. rgrepце для мене, і остання пропозиція про next-error previous-errorце фантастично! Моя єдина суперечка - це те, що все брудне виконання команд виводиться на початку буфера.
Роберт

11

Я із задоволенням використовую M-x find-grep-diredроками. Він повертає результати у вигляді рознесеного буфера, який ви могли б використовувати.


У мене виникли певні труднощі з отриманням перехресного посилання, яке пов'язувало роботу з цим. Це конфігурація досить неприємна ( find-ls-option), і, нарешті, ви закінчите щось досить багатослівне, оскільки воно не працює, не маючи дати перед назвою файлу!
Роберт

5

Рішення 1 (найкраще рішення):

Встановіть консультацію ( https://github.com/abo-abo/swiper/blob/master/counsel.el )

Потім M-x counsel-git-grep.

Не потрібно налаштовувати (git знає корінь проекту та файли, які потрібно виключити). І те, git grepі counselефективно.

Проектом потрібно керувати git.

адвокат вимагає режиму плюща.

Рішення 2:

Це рішення використовує grep і працює над будь-яким проектом. Він поступається Рішенню 1, оскільки він повільніше і потребує налаштування вручну. Він також базується на режимі плюща.

(defvar simple-project-root "~/.emacs.d")
(defun simple-grep ()
  (interactive)
  (unless (featurep 'ivy)
    (require 'ivy))
  (let* ((default-directory (file-name-as-directory simple-project-root))
         (keyword (read-string "Keyword:")))
    (ivy-read (format "Grep at %s:" simple-project-root)
              (split-string (shell-command-to-string (format "grep -rsnI %s ." keyword)) "\n" t)
              :action (lambda (val)
                        (let* ((lst (split-string val ":"))
                               (linenum (string-to-number (cadr lst))))
                          ;; open file
                          (find-file (car lst))
                          ;; goto line if line number exists
                          (when (and linenum (> linenum 0))
                            (goto-char (point-min))
                            (forward-line (1- linenum))))))))

Щоб налаштувати simple-project-root, потрібно створити .dir-locals.el , див. Https://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.html для отримання технічних деталей

Код у рішенні 2 - лише прототип. Моя реальна реалізація набагато складніша. Дивіться counsel-etags-grepна https://github.com/redguardtoo/counsel-etags/blob/master/counsel-etags.el

Підсумок:

Це найкращі два рішення, які я знаю.

Якщо існують будь-які інші кращі рішення, їм потрібно принаймні вирішити проблеми нижче, щоб бути готовими до виробництва,

  • як отримати ключове слово для вимкнення (наприклад, отримати ключове слово з вибраного регіону)

  • уникнути ключового слова

  • якщо існує більш ефективна програма grep, ми повинні використовувати її (ripgrep, the_silver_searcher / ag, ... і т.д.), або інший запасний варіант grep за замовчуванням

  • вікно кандидата має використовувати повну ширину екрану, і користувачі можуть інтерактивно фільтрувати кандидатів (саме тому люди використовують плющ або кермо)

  • нам слід показати відносний шлях у вікні кандидата

  • можливість повторного використання попереднього результату. Тож попередній результат слід зберегти. Ви можете використовувати ivy-resumeз ivyабо helm-resumeвідhelm

  • Коли ви зберігаєте попередній вилучений результат, контекст попереднього результату також повинен бути збережений. Наприклад, у коді рішення 2. default-directoryє контекст. Дивіться https://github.com/abo-abo/swiper/isissue/591 для отримання більш детальної інформації.

  • Необхідно використовувати розширений регулярний вираз, оскільки він простіший і його вже використовує counsel-git-grepthe_silver_searcher / ag.


4

Я хотів би додати ще одне рішення до рішення @chen bin, яке також використовує counsel(але для цього вам не потрібно підтримувати проект git).

Потрібно встановити ag (срібний пошук) і counselнадає команду, counsel-agяка шукає поточний каталог для введеного рядка.

Якщо ви хочете здійснити пошук в рамках проекту (не тільки в поточній робочій директорії), додайте це до свого .emacs: -

  (defun rag/counsel-ag-project-at-point ()
    "use counsel ag to search for the word at point in the project"
    (interactive)
    (counsel-ag (thing-at-point 'symbol) (projectile-project-root)))

Ця функція використовуватиме agдля рекурсивного пошуку кореневого каталогу проекту.

Редагувати : вищевказана функція за замовчуванням символу в точці пошуку. Якщо вам не подобається така поведінка, замініть (thing-at-point 'symbol)на nil. І якщо ви хочете, щоб результати пошуку були у власній буферній пресіC-c C-o

Edit2 : якщо ви ripgrepвстановили, ви можете замінити counsel-agз counsel-rgв наведеній вище функції , і це буде так само , як нормально :)


Чи projectile-project-rootкорисно знайти корінь проекту Rails?
Борис Стітнікі

Так, поки це дійсний проект снаряду, він буде працювати. Я думаю, був якийсь пакет, який називався рейки снаряда.
Чакраварті Рагунандан

Чому ви назвали цю функцію rag/...?
Борис Стітнікі

Це загальний стиль, який люди часто використовують при написанні власних функцій (ви можете бачити, що це робиться багатьма іншими, якщо переглядати їх конфігурацію emacs). Усі визначені мною функції починаються з rag/префікса, і це полегшує їх пошук під M-x:)
Chakravarthy Raghunandan

Ic, це ваше ім'я :-)
Борис Стітнікі

2

Ось приклад спеціальної функції grep, яка рекурсивно збирає вміст файлу (використовуючи повторне вираження для пошукового терміна) у каталозі та його підкаталогах та відображає результати з рядками контексту до та після. Вбудовані compile.elта grep.elбібліотеки передбачають кілька методів переходу до місця у файлі, що містить результати пошуку. Не потрібно встановлювати нічого іншого, щоб цей приклад працював - все, що потрібно, - це повна версія Emacs та комп'ютер, на якому grepвстановлена ​​утиліта. Змінна grep-programможе бути налаштована так, щоб вона вказувала на певне місце grepутиліти, якщо за замовчуванням недостатньо.

(defun recursive-grep ()
"Recursively grep file contents.  `i` case insensitive; `n` print line number;
`I` ignore binary files; `E` extended regular expressions; `r` recursive"
(interactive)
  (let* ((search-term (read-string "regex:  "))
         (search-path
           (directory-file-name (expand-file-name (read-directory-name "directory:  "))))
         (default-directory (file-name-as-directory search-path))
         (grep-command
           (concat
             grep-program
             " "
             "-inIEr --color=always -C2"
             " "
             search-term
             " "
             search-path)))
    (compilation-start grep-command 'grep-mode (lambda (mode) "*grep*") nil)))

Хоча питання не спрямований на те, як одночасно змінювати кілька файлів, які повертаються як результати за допомогою наведеної вище функції grep, я вважаю це дуже корисним у використанні multiple-cursorsта wgrep. Це робить модифікацію кількох файлів одним махом вітерцем. Однак зазначені бібліотеки потрібно буде встановити, якщо ці функції бажані.
законник

Яка перевага використання цього над вбудованим rgrep?
nпостаs

1
@npostavs - Я виявив, що цей вбудований процес rgrepзабирає багато часу, щоб налаштувати мої бажані критерії пошуку регулярних виразів, і я вирішив жорстко кодувати все в користувацькій функції (якою я користуюся кілька разів щодня). Якщо ви хочете написати альтернативну відповідь, яка описує, як налаштувати rgrep, це буде корисним для інших читачів форуму в майбутньому.
законник
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.