如何在所有 Sublime Text 窗口中按名称查找打开文件的选项卡

如何在所有 Sublime Text 窗口中按名称查找打开文件的选项卡

答案如下https://stackoverflow.com/questions/20519040/search-in-all-files-in-a-project-in-sublime-text-3使用 Sublime Text 2 搜索打开的标签页中的所有内容告诉如何搜索打开的文件按其内容,使用++FWhere: <open files>

但当我尝试这个时,它只搜索在选项卡中打开的文件在当前窗口中。如果我打开了两个窗口,每个窗口有 10 个选项卡,并且在其中一个窗口中使用++ ,则搜索结果会告诉我搜索了 10 个文件,而不是 20 个。F

现在,如果我打开了十几个窗口,我不想循环浏览每个窗口来搜索我想要的文件。(是的,我应该清理杂乱的东西,但这不是我要问的问题。)

有没有办法找到打开的文件任何打开的窗口

我还想找到该文件按名字(或标签标题,通常相同)而不是按内容。但如果我可以搜索所有打开的窗口,我会满足于按内容搜索。

更新:看起来应该起作用的东西

我发现像这样的包Emacs Pro 基础知识扩展标签切换器,两者都描述了允许您按名称切换到其他视图/缓冲区/选项卡的功能。 这两个包都明确表示默认行为是这样做在所有群体中(我认为这意味着跨所有窗口)。但是当我尝试它们时,只有来自同一窗口的选项卡才会显示在列表中以供选择。

内置Goto>Goto Anything菜单项的行为方式相同(十年前未得到答复的技术支持论坛请求)。

这让我怀疑 Mac 版本是否存在某些特定问题,导致所有这些工具无法访问其他窗口中的选项卡。

答案1

你可以用一个小包来解决这个问题。这是我的尝试:winfinder在 Sublime 3 包文件夹下创建一个名为“ ”的文件夹(在 Mac 上,这将是~/Library/Application Support/Sublime Text 3/Packages/winfinder)。

main.py接下来,在该文件夹中创建一个包含以下内容的文件:

import sublime
import sublime_plugin

class WinFindCommand(sublime_plugin.TextCommand):

    def search(self, search_string):
        l = []
        for w in sublime.windows():
            for sh in w.sheets():
                fn = sh.view().file_name()
                if fn is not None:
                    if search_string.lower() in fn:
                        l.append(fn + "\n")
        if len(l) > 0:
            v = sublime.active_window().new_file()
            v.set_name("SearchResults")
            v.run_command("insert",{"characters": str(len(l)) + " matches:\n\n"})
            v.run_command("insert",{"characters": "\n".join(l)})
        else:
            sublime.message_dialog("No match found.")


    def run(self, edit):
        w = sublime.active_window()
        w.show_input_panel("Search text", "", self.search, None, None)

现在我们需要一种方法来调用该功能。这可以通过在同一个文件夹中创建一个名为的文件来完成main.sublime-commands。内容如下:

[
    { "caption": "WindowFind: find in window title", "command": "win_find" },
]

用法

如果您打开命令面板并输入“ WindowFind”,您应该会看到该命令。按 [ENTER],包将提示您在所有窗口的所有选项卡中搜索要搜索的搜索字符串。如果没有匹配,则会显示一条消息。

如果匹配,则会打开一个名为“SearchResults”的新选项卡,其中包含搜索结果:

3 matches:

/Users/your_user/notes/daylog.txt

/Users/your_user/Documents/2018/paychecks.csv

/Users/your_user/source/python/daily_tweets/daily.py

(搜索字符串是“ay”)——只需在 Sublime 3 上测试一下,就可以了。谢谢你的想法,这很有帮助!:-)

答案2

使用@Arminius 的想法回答,我修改了“切换到视图”代码Emacs Pro Essentials 插件,这样它现在就可以与所有窗口中的视图一起使用。以下是生成的代码main.py

# coding=utf-8
# Sublime plugin to search open files by filename, across all windows.
# See problem statement at https://superuser.com/questions/1327172/how-to-find-the-tab-of-an-open-file-by-name-in-all-sublime-text-windows

# Code adapted from https://github.com/sublime-emacs/sublemacspro/blob/master/switch_to_view.py
# and https://superuser.com/a/1328545/75777

import sublime, sublime_plugin, os


#
# Switch buffer command. "C-x b" equiv in emacs. This limits the set of files in a chooser to the
# ones currently loaded. Do we sort the files by last access? like emacs

class SwitchToViewCommand(sublime_plugin.TextCommand):
    def run(self, util, current_group_only=False, preview=False, completion_components=2, display_components=1):
        self.preview = preview
        self.completion_components = completion_components
        self.display_components = display_components
        window = self.window = sublime.active_window()
        self.group = window.active_group()
        # was: self.views = ViewState.sorted_views(window, window.active_group() if current_group_only else None)
        self.views = [sh.view() for w in sublime.windows() for sh in w.sheets()]
        ## TODO: sort the above views?
        # if window.num_groups() > 1 and not current_group_only:
        #     self.group_views = set(view.id() for view in sorted_views(window, window.active_group()))
        # else:
        #     self.group_views = None
        self.roots = get_project_roots()
        self.original_view = window.active_view()
        self.highlight_count = 0

        # swap the top two views to enable switching back and forth like emacs
        if len(self.views) >= 2:
            index = 1
        else:
            index = 0
        window.show_quick_panel(self.get_items(), self.on_select, 0, index, self.on_highlight)

    def on_select(self, index):
        if index >= 0:
            # Does this work even on views that aren't in self.window?
            v = self.views[index]
            if v.window() is not self.window:
                try:
                    v.window().bring_to_front()
                    v.window().focus_window()
                    # Strangely, I get the error 'Window' object has no attribute 'focus_window'
                    # even though the documentation says it should be there in this version of ST.
                except AttributeError as e:
                    print(f"{type(e).__name__} at line {e.__traceback__.tb_lineno} of {__file__}: {e}")
            v.window().focus_view(self.views[index])
        else:
            self.window.focus_view(self.original_view)

    def on_highlight(self, index):
        if not self.preview:
            return
        self.highlight_count += 1
        if self.highlight_count > 1:
            # if self.group_views is None or self.views[index].id() in self.group_views:
            self.window.focus_view(self.views[index])

    def get_items(self):
        if self.display_components > 0:
            return [[self.get_path(view), self.get_display_name(view)] for view in self.views]
        return [[self.get_path(view)] for view in self.views]

    def get_display_name(self, view):
        mod_star = '*' if view.is_dirty() else ''

        if view.is_scratch() or not view.file_name():
            disp_name = view.name() if len(view.name()) > 0 else 'untitled'
        else:
            disp_name = get_relative_path(self.roots, view.file_name(), self.display_components)

        return '%s%s' % (disp_name, mod_star)

    def get_path(self, view):
        if view.is_scratch():
            return view.name() or ""

        if not view.file_name():
            return '<unsaved>'

        return get_relative_path(self.roots, view.file_name(), self.completion_components)

# From https://github.com/sublime-emacs/sublemacspro/blob/master/lib/misc.py
# Returns the relative path for the specified file name. The roots are supplied by the
# get_project_roots function, which sorts them appropriately for this function.
#
def get_relative_path(roots, file_name, n_components=2):
    if file_name is not None:
        if roots is not None:
            for root in roots:
                if file_name.startswith(root):
                    file_name = file_name[len(root) + 1:]
                    break
        # show (no more than the) last 2 components of the matching path name
        return os.path.sep.join(file_name.split(os.path.sep)[-n_components:])
    else:
        return "<no file>"

# Get the current set of project roots, sorted from longest to shortest. They are suitable for
# passing to the get_relative_path function to produce the best relative path for a view file name.
#
def get_project_roots():
    window = sublime.active_window()
    if window.project_file_name() is None:
        roots = None
    else:
        project_dir = os.path.dirname(window.project_file_name())
        roots = sorted([os.path.normpath(os.path.join(project_dir, folder))
                       for folder in window.folders()],
                       key=lambda name: len(name), reverse=True)
    return roots

# # From ViewState. But I'm not using these right now. Don't really want to build the data structure of ViewStates.
#
# # Returns a list of views from a given window sorted by most recently accessed/touched. If group
# # is specified, uses only views in that group.
# #
# # @classmethod
# def sorted_views(window, group=None):
#     views = window.views_in_group(group) if group is not None else window.views()
#     states = [find_or_create(view) for view in views]
#     sorted_states = sorted(states, key=lambda state: state.touched, reverse=True)
#     return [state.view for state in sorted_states]
#
#
# # Finds or creates the state for the given view. This doesn't imply a touch().
# #
# # @classmethod
# def find_or_create(cls, view):
#     state = cls.view_state_dict.get(view.id(), None)
#     if state is None:
#         state = ViewState(view)
#     return state

相关内容