Как я могу отфильтровать файл по строкам, содержащим строку в Sublime Text 2?

74

Я хочу отфильтровать файл, который я редактирую, в Sublime Text 2, чтобы строки содержали определенную строку, если возможно, включая регулярные выражения.

Рассмотрим следующий файл:

foo bar
baz
qux
quuux baz

После фильтрации baрезультат должен быть:

foo bar
baz
quuux baz

Как я могу это сделать?

Даниэль Бек
источник

Ответы:

87

Sublime Text 2 - это расширяемый редактор с Python API . Вы можете создавать новые команды (называемые плагинами ) и делать их доступными из пользовательского интерфейса.

Добавление базового плагина TextCommand для фильтрации

В Sublime Text 2 выберите Инструменты »Новый плагин и введите следующий текст:

import sublime, sublime_plugin

def filter(v, e, needle):
    # get non-empty selections
    regions = [s for s in v.sel() if not s.empty()]

    # if there's no non-empty selection, filter the whole document
    if len(regions) == 0:
        regions = [ sublime.Region(0, v.size()) ]

    for region in reversed(regions):
        lines = v.split_by_newlines(region)

        for line in reversed(lines):
            if not needle in v.substr(line):
                v.erase(e, v.full_line(line))

class FilterCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        def done(needle):
            e = self.view.begin_edit()
            filter(self.view, e, needle)
            self.view.end_edit(e)

        cb = sublime.get_clipboard()
        sublime.active_window().show_input_panel("Filter file for lines containing: ", cb, done, None, None)

Сохранить как filter.pyв~/Library/Application Support/Sublime Text 2/Packages/User

Интеграция с пользовательским интерфейсом

Чтобы добавить этот плагин в меню « Правка» , выберите « Настройки» ... »Просмотреть пакеты и откройте Userпапку. Если файл с именем Main.sublime-menuне существует, создайте его. Добавьте или установите следующий текст в этот файл:

[
    {
        "id": "edit",
        "children":
        [
            {"id": "wrap"},
            { "command": "filter" }
        ]
    }
]

Это вставит filterвызов команды (по сути, filterпреобразуется в FilterCommand().run(…)для вызова плагина и Фильтр для метки меню) чуть ниже wrapкоманды. Смотрите шаг 11 здесь для более подробного объяснения, почему это так.

Чтобы назначить сочетание клавиш, откройте и отредактируйте файл Default (OSX).sublime-keymapв OS X или эквивалент для других систем и введите следующее:

[  
    {   
        "keys": ["ctrl+shift+f"], "command": "filter"
    }  
]  

Это назначит ярлык Fдля этой команды.


Чтобы команда появилась в палитре команд , вам нужно создать файл с именем Default.sublime-commands(или отредактировать существующий) в Userпапке. Синтаксис похож на файл меню, который вы только что отредактировали:

[
    { "caption": "Filter Lines in File", "command": "filter" }
]

Несколько записей (заключенных в фигурные скобки) должны быть разделены запятыми.

 Скриншоты интеграции поведения и пользовательского интерфейса

Команда, как она реализована, отфильтрует все строки, являющиеся частью выделения (целые строки, а не только выделенные части) или, если выбор не существует, весь буфер для подстроки, введенной в поле ввода ( по умолчанию это - возможно бесполезный многострочный - буфер обмена) после запуска команды. Его можно легко расширить, например, для поддержки регулярных выражений или оставить только строки, не соответствующие определенному выражению.

Пункт меню

Команда в меню

Ввод палитры команд

Команда с другой меткой в ​​палитре команд

редактор

Пользователь вводит текст для фильтрации файла с

Результат после выполнения команды

Добавление поддержки регулярных выражений

Чтобы добавить поддержку регулярных выражений, используйте вместо этого следующие сценарии и фрагменты:

filter.py:

import sublime, sublime_plugin, re

def matches(needle, haystack, is_re):
    if is_re:
        return re.match(needle, haystack)
    else:
        return (needle in haystack)

def filter(v, e, needle, is_re = False):
    # get non-empty selections
    regions = [s for s in v.sel() if not s.empty()]

    # if there's no non-empty selection, filter the whole document
    if len(regions) == 0:
        regions = [ sublime.Region(0, v.size()) ]

    for region in reversed(regions):
        lines = v.split_by_newlines(region)

        for line in reversed(lines):

            if not matches(needle, v.substr(line), is_re):
                v.erase(e, v.full_line(line))

class FilterCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        def done(needle):
            e = self.view.begin_edit()
            filter(self.view, e, needle)
            self.view.end_edit(e)

        cb = sublime.get_clipboard()
        sublime.active_window().show_input_panel("Filter file for lines containing: ", cb, done, None, None)

class FilterUsingRegularExpressionCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        def done(needle):
            e = self.view.begin_edit()
            filter(self.view, e, needle, True)
            self.view.end_edit(e)

        cb = sublime.get_clipboard()
        sublime.active_window().show_input_panel("Filter file for lines matching: ", cb, done, None, None)

Main.sublime-menu:

[
    {
        "id": "edit",
        "children":
        [
            {"id": "wrap"},
            { "command": "filter" },
            { "command": "filter_using_regular_expression" }
        ]
    }
]

Default (OSX).sublime-keymap:

[  
    {   
        "keys": ["ctrl+shift+f"], "command": "filter"
    },
    {
        "keys": ["ctrl+shift+option+f"], "command": "filter_using_regular_expression"
    }
]  

Вторая команда плагина, Filter Using Regular Expression, будет добавлена ​​ниже пункта меню Filter .

Default.sublime-commands:

[
    { "caption": "Filter Lines in File", "command": "filter" },
    { "caption": "Filter Lines in File Using Regular Expression", "command": "filter_using_regular_expression" }
]
Даниэль Бек
источник
2
Разве вы не хотите опубликовать это как пакет один день?
slhck
1
@slhck Кто-то уже сделал (с соответствующей атрибуцией), см. ответ NovicePhysicist. Из того, что я прочитал в коде, этот ответ также немного улучшился по сравнению с этим ответом.
Даниэль Бек
Круто, я этого не заметил!
slhck
Что это за тема у вас с SublimeText, которая дает такие приятные цвета? Или это просто изменение цвета окна?
pal4life
1
@ pal4life: это называется Solarized (Light) . Я думаю, что Sublime Text даже поставляется с ним. Возможно, я установил альтернативный вариант, поэтому цвета могут не совпадать. Скриншоты сделаны в OS X, так что отсюда граница окна и строка заголовка.
Даниэль Бек
83

Существует также алгоритм фильтрации строк для бедного человека (или он ленивый?):

  1. Выберите интересующую строку
  2. Нажмите Alt+, F3чтобы перейти в режим нескольких курсоров во всех случаях
  3. Нажмите Control+, Lчтобы выделить всю строку (на каждой строке курсора)
  4. Копировать-вставить выделение в другой буфер
Олоф Бьярнасон
источник
2
Это в значительной степени самое простое решение. Браво!
Gillytech
Спасибо! Я предпочитаю не устанавливать / изучать другой плагин как можно дольше - Alt + F3 у меня в мышечной памяти, так что вышеприведенное решение на самом деле не так уж и сложно для меня.
Олоф Бьярнасон
Вы можете заменить шаги 3 и 4 одним шагом: Ctrl + L.
Андрес Риофрио
1
Хорошее простое решение! Я бы заменил шаг 3 с Ctrl-L на Home, Shift-End, так что между вхождениями нет пустых строк.
Jslap
4
Это изменило мою жизнь к лучшему. Ничто никогда не будет прежним.
Шоусон
49

Теперь есть плагин для фильтрации строк: https://github.com/davidpeckham/FilterLines.
Он позволяет фильтровать и сворачивать код на основе строк или регулярных выражений.


Плагин Sublime Text Filter от Дэвида Пекхэма

AllanLRH
источник
4
Только что установил этот плагин - ИДЕАЛЬНО для работы. Берет существующий файл, позволяет ввести фразу фильтра и поместить результаты в новую вкладку.
Ник
4
Согласен, до сих пор я только мечтал иметь такую ​​функциональность в моем текстовом редакторе.
Michael12345 30.01.14
1
Этот плагин действительно потрясающий!
Девид
Пришел сюда, потому что коллега упомянул кое-что о «Keep Lines» для emacs и его полезности. Даже не знал, что мне нужен этот плагин, очень нравится!
brandon927
14

Вы можете использовать встроенные возможности Sublime, чтобы сделать это от 3 до 7 нажатий клавиш (не включая регулярное выражение для сопоставления).

Шаг 1: мульти-выбрать все совпадающие строки

Вариант 1: чтобы выбрать несколько строк, содержащих подстроку

  1. Выберите интересующую строку.
  2. Нажмите Alt+, F3чтобы выбрать несколько событий.
  3. Нажмите Ctrl+ L(Расширить выделение до строки).

Вариант 2: чтобы выбрать несколько строк, соответствующих регулярному выражению

  1. Нажмите Ctrl+, Fчтобы открыть ящик поиска.
  2. Убедитесь, что сопоставление регулярных выражений включено ( Alt+ Rдля переключения).
  3. Введите регулярное выражение.
  4. Нажмите Alt+, Enterчтобы выбрать все совпадения.
  5. Нажмите Ctrl+ L(Расширить выделение до строки).

Шаг 2: Сделайте что-нибудь с этими строками

Вариант 1: избавиться от всех не выделенных строк

  1. Нажмите Ctrl+, Cчтобы скопировать.
  2. Нажмите Ctrl+, Aчтобы выбрать все.
  3. Нажмите Ctrl+, Vчтобы заменить выделение соответствующими строками.

Вариант 2: Для того, чтобы избавиться от всех линий, которые выбранные

  1. Хит Ctrl+ Shift+ K(Удалить строку).

Вариант 3: Извлечь выделенные строки в новый файл

  1. Нажмите Ctrl+, Cчтобы скопировать.
  2. Нажмите Ctrl+, Nчтобы открыть новый файл.
  3. Нажмите Ctrl+, Vчтобы вставить.
Андрес Риофрио
источник
Это отличный список команд!
Chustar
Супер, а есть ли способ убрать пустые строки после вставки?
Сергей Сенков
1
@SergeySenkov Конечно! (1) Нажмите Ctrl + F, чтобы открыть ящик поиска. (2) Убедитесь, что сопоставление регулярных выражений включено (Alt + R для переключения). (3) Введите «\ n \ n +» (соответствует двум или более последовательным переводам строки). (4) Нажмите Alt + Enter, чтобы выбрать все совпадения. (5) Нажмите Enter, чтобы заменить все совпадения одной новой строкой.
Андрес Риофрио,