【问题标题】:How to format "one line html" as a pretty document in sublime? [duplicate]如何将“一行html”格式化为崇高的漂亮文档? [复制]
【发布时间】:2013-02-14 09:09:42
【问题描述】:

我有一个 html 源文件,其中只包含如下一行:

<html><head>test</head><body>wow</body></html>

,我想将其格式化如下:

<html>
    <head>
        test
    </head>
    <body>
        wow
    </body>
</html>

,我使用了命令:Edit-> Line-> Reindent,但它不起作用。

【问题讨论】:

标签: sublimetext3


【解决方案1】:

如果它是简单的,我可以录制一个缩进标签的宏(工具 -> 录制宏),然后保存并重复使用这个宏。不知道这是否有帮助。

【讨论】:

    【解决方案2】:

    在 Sublime Text 中试试这个:

    1. 突出显示第一个标签中的最后一个字符:“&gt;
    2. 使用Find > Quick Add Next (Command+D on Mac 或 Ctrl+D on电脑)

    您现在将在多个选择中突出显示所有出现,将插入符号移动到标记的末尾并按回车键插入您需要的所有新行。

    祝你好运

    【讨论】:

    • 我根本不知道Quick Add Next 命令。好主意!
    【解决方案3】:

    我的印象是 Sublime 也提供了这种能力。当我发现它不是时,我有了使用正则表达式的想法。尽管 regex 通常被认为不适合解析 XML/HTML,但我发现这种方法在这种情况下是可以接受的。据说 Sublime 也可以通过插件高度定制,所以我认为这将是一种方式。

    Sublime 插件

    说实话,我本可以想到 tidy 或者至少怀疑肯定有插件可以解决您的问题。相反,我最终编写了我的第一个 sublime 插件。我只用你的输入和预期的输出对它进行了测试,它满足了,但它肯定离可靠地工作还很远。但是,我在这里发布它以分享我所学到的东西,它仍然是问题的答案。

    打开一个新缓冲区 (Ctrl+n) 并在菜单“工具”中选择“New Plugin...”条目慷慨地生成一个小“Hello World!”示例插件(作为 Python 模块),它为实现 sublime_plugin.TextCommand 子类提供了一个很好的模板。 TextCommand 提供对活动缓冲区/当前打开文件的访问。像它的亲戚WindowCommandApplicationCommand 一样,它需要覆盖一个运行方法。

    official API Reference 建议通过阅读随 Sublime 构建分发并位于相对于 Sublime 配置路径的Packages/Default 的示例源来学习。更多示例可以在website 上找到。有moreon 互联网。

    处理选定的文本

    要为您的问题找到解决方案,我们主要需要访问代表活动文本缓冲区的View 对象。好在我们即将实现的TextCommand子类有一个,我们可以方便地向它查询当前选中的区域及其选中内容,处理符合我们需要的选中文本,然后用我们的偏好替换选中的文本。

    总结一下字符串操作:有四个正则表达式,每个都匹配元素类&lt;start-tag&gt;&lt;empty-tag/&gt;&lt;/close-tag&gt;text-node之一。假设我们所有的标记文本都被这些覆盖,我们将选择中的每一行都放入匹配的子字符串中。然后每行重新对齐这些。完成此操作后,我们通过记住缩进其前身包含开始标记的每一行来应用简单的缩进。包含结束标记的行立即取消缩进。

    使用 Python 正则表达式的group addressing 特性,我们可以确定每一行的缩进并相应地对齐下一行​​。事不宜迟,这将导致内部一致的缩进标记,但不考虑选择之外的行。通过将选择扩展到封闭元素,或者至少符合相邻行的缩进级别,可以轻松改善结果。总是可以使用default commands

    另一件需要注意的事情是将键绑定到插件命令和贡献菜单条目。可能somehow 是可能的,Packages/Default 中的默认.sublime-menu.sublime-commands 文件至少给出了一个想法。无论如何,这里有一些代码。它必须保存在Packages/User/whatever.py 下,并且可以从 Sublime Python 控制台 (Ctrl+`) 调用,如下所示:view.run_command('guess_indentation')

    代码

    import sublime
    import sublime_plugin
    import re
    
    class GuessIndentationCommand(sublime_plugin.TextCommand):
        def run(self, edit):
            view = self.view
            #view.begin_edit()
            # patterns
            start_tag = '<\w+(?:\s+[^>\/]+)*\s*>'       # tag_start
            node_patterns = [start_tag, 
                            start_tag[:-1]+'\/\s*>',    # tag_empty
                            '<\/\s?\w+\s?>',            # tag_close
                            '[^>\s][^<>]*[^<\s]']       # text_node
            patterns = '(?:{0})'.format('|'.join(node_patterns))
            indentors = re.compile('[ \t]*({0})'.format('|'.join(node_patterns[:1])))
            unindentors=re.compile('[ \t]*({0})'.format(node_patterns[2]))
            # process selected text
            for region in view.sel():
                # if selection contains text:
                if not region.empty():
                    selection = view.substr(region)
                    expanded = []
                    # divide selected lines into XML elements, if it contains more than one
                    for line in selection.split('\n'):
                        elements = re.findall(patterns, line)
                        if len(elements)>0:
                            expanded += elements
                        else:
                            expanded.append(line)
                    # indent output
                    indent=0
                    indented = []
                    for line in expanded:
                        match = unindentors.match(line)
                        if match:
                            indent = max(0, indent-1)
                        # append line to output, unindented if closing tag
                        indented.append('\t'*indent+line)
                        if match:
                            continue
                        # test for possible indentation candidate
                        # indentation applies to the NEXT line
                        match = indentors.match(line)
                        if match:
                            indent+=1
                    # replace selection with aligned output
                    view.replace(edit, region, '\n'.join(indented))
    

    【讨论】:

    • 这是合适的解决方案。尽管这看起来很难执行 - 实际上可以在 1 分钟内完成。答案的简短版本(对于 mac os): 1. 选择 Tools->Developer->New plugin 2. 将上面的代码复制并粘贴到工作区中 3. 选择 File->Save as,将其命名为 guess_indentation.py 4. 打开一个带有 HTML 代码的选项卡 5. 选择 V​​iew->Console 6. 键入 view.run_command('guess_indentation') 7. 选择 Edit->Line->Reindent 8. 为这个出色的解决方案点赞
    猜你喜欢
    • 1970-01-01
    • 2019-09-24
    • 2015-07-24
    • 2021-10-20
    • 2022-01-11
    • 2019-12-15
    • 2016-02-25
    • 2016-09-14
    • 2019-06-07
    相关资源
    最近更新 更多