• sublime优化之路


    sublime优化之路

    Emacs的忠粉竟然开始写sublime的优化之路,所谓世事难料。Emacs的可配置化,可玩性真是无与伦比,里面的插件丰富,质量高,更新频繁。但有一个致命的缺点,就是在公司有安全扫描的时候,启动和运行非常缓慢。因为在自己的电脑上面运行非常快,之前以为只是个别公司的安全控件导致极度缓慢,时不时会僵死失去响应,很烦人,但经历过几个公司都一样,就想要换一换了。本来是绝世宝刀屠龙刀,但挥舞不动也只能属于鸡肋应用了。

    而Sublime Text基本上各个公司的软件库里面都有,下载下来主要当做notepad记事本的替换品,体验之后,发现界面很漂亮,快,真的是快,并且相对比较稳定,毕竟商业化产品。后来就想要不用Sublime替换Emacs,了解之后,发现Sublime使用python做为插件语言,比较好上手,使用范围也广,做为第二主要语言保持熟悉也挺好的,这也是放弃VIM的原因。

    粗略使用Sublime Text安装插件,还是挺惊喜的。安装速度很快,Emacs的安装之前有自己的elpa,Malpa,国内速度很慢,时不时不能使用,但可以切换国内源。后来的包管理基本上切换到github上去了,那更糟糕了。github基本上很难把包下载完,更新一下就挂了。这里也要吐槽一下,一个Emacs怎么需要那么多的包,安装完起码4、500MB了,这还是个编辑器吗?VS code也就400多MB。

    顺便说一下VS code,本来以为是轻量化的编辑器,实际用下来也不怎么轻量化了,体积不小,启动速度和sublime也没得比。里面的包安装体验还是很不错的,整体感觉也是中规中矩。它基于electron开发,扩展语言应该用的node-js,这个写vue什么的也还熟悉,只是更新起来也是一大坨。

    最后说一下,Sublime和VS code都是TextMate那边模仿过来的,TextMate是Mac下的著名的文本编辑器软件,与BBEdit一起并称苹果机上的Emacs和Vim,之前是收费软件,首创的Snippet、多鼠标操作等也被其他编辑器吸收,开发二代耗时几年,再回过头来,市场也丢失大部分,干脆就开源了。所以,可以这么理解,TextMate是Mac下比肩Emacs的编辑器,而Sublime将TextMate扩展到各个平台。

    推荐的插件

    Package

    • Package control
      这个必须安装,安装这个之后才方便安装其他的插件。安装完成之后可以通过Command Palette 进行调用。Command Palette中可以支持所有注册的命令的fuzzy模糊搜索并调用。所有的操作都要定义为 Command,执行 Command 有三种方式,一是刚刚讲的 Command Palette,先通过 .sublime-command 注册命令,然后搜索过滤出命令;二是通过 .sublime-keymaps 绑定快捷键进行执行;三是通过.sublime-menu注册到菜单栏里面去。这三种方式可以共存。当然,严格来讲也还可以通过Console进行命令的调用,但这种就不方便了,除非调试开发,一般很少使用。
    • PackageResourceViewer
      默认安装的插件是.sublime-package后缀的,这个实际上是一个zip包,可以用压缩软件直接打开。这个插件可以用来预览或者是解压这个压缩包里面的单个源码,或者解压几个或全部的插件包。
      安装 PackageResourcesViewer,通过 PackageResourcesViewer:Open Resource修改想要调整的代码,保存就会在 packages 文件夹下面创建原有插件的目录结构和python源码文件,然后,在这个文件里面进行修改和覆盖。
    • OverrideAudit
      这个插件和前面的 PackageResourceViewer类似,也可以打开和解压插件包里面的单个文件,但没有批量解压这个插件包的功能,否则就可以不用前面那个插件了。这个插件是有菜单栏进行使用的,功能如菜单,也是比较好理解的。可以查看插件内容,也可以汇总插件的安装情况,可以查看哪些插件有解压。因为我们有时需要对安装的插件进行一些扩展和调整,这个插件也可以发现原插件是否有更新,哪些文件被覆盖了,等等。如果喜欢自己修改插件,个人觉得这个也是必须要安装的。具体的功能建议安装之后自己好好体验一下。

    Emacs

    • Emacs Pro Essentials
      这个作为一个重度Emacs使用者,必须要安装的,装完之后,大部分都文本操作快捷键之类的,还是可以保持一样的。分屏pane(emacs的window)操作,窗口window(emacs的frame)跳转,view(emacs的buffer)切换等基本还是一致的。但要说到里面的文件操作,那可太难用了。Emacs的交互panel比Sublime的可以高级灵活多了。Sublime的quick_panel只能给定待选列表,然后从中进行选择,对于输入框的内容无法获取,也没有监听输入框的变化的回调函数,那就没法输入的时候,动态的调整待选择的内容。所以,后面讲到的文件的操作,要废很大的劲去绕过去,通过input_panel和quick_panel来回倒腾,或者只能在input_panel里面做简单的提示,而不能自动补全,相当别扭,这个和Emacs比起来还是差了好多。更不用说,根据拼音首字母进行模糊搜索和过滤的能力了,sublime看起来很难实现了。

    Markdown

    sublime的markdown原生就有还不错的支持,安装下面几个插件就更好了。

    • MarkdownEditing
      这个提供一些编辑和跳转的增强。
    • MarkdownImages(废弃)
      可以在编辑页面里面保存的时候自动显示图片内容,还是比较实用的。只是会导致sublime闪动,鼠标乱跳。
      解决图片预览的方案
    • MarkdownPreview
      可以和 LiveReload 配合在浏览器中实现实时预览功能。用得比较少,一般情况,也知道自己的文章最后会呈现成什么样,当然,看一看也没有什么不好的。
    • LiveReload
      可以在保存文档的时候动态的刷新浏览器中的预览页面。需要在浏览器里面安装插件,比如chrome里面要安装livereload.zip插件,国内的插件市场应该打不开,可以离线安装,具体的安装方法可以参考 http://www.xitongzhijia.net/soft/196180.html

    KeybindingHelper

    这个作为插件开发,可以用来了解快捷键绑定了什么命令,通过 Ctrl+super+` 将按键记录窗口打开,可以看到调用了什么命令。

    TrailingSpaces(废弃)

    可以显示和删除行尾的空白空格,对于一个强迫症者而言,这个是必须的。但看了一下sublime自带的配置,发现sublime自己的功能就能很好的满足要求,应该性能也会更好:

        "draw_white_space": ["leading_mixed_tabs", "trailing_all", "selection"],
        "trim_trailing_white_space_on_save": "not_on_caret",
    

    AutomaticPackageReloader(废弃)

    可以自动加载修改的package,但实际效果不太好,使用简单的 Package reloader

    Package Reloader

    可以通过.reload.json文件设置包的加载文件和顺序,比较简单可靠。但实际上,对于不同版本的python不支持。默认是3.3,如果里面有.python-version设置为3.8,则结果是不对的。因为还是加载到3.3里面去了。

    Debugger

    采用最新的DAP(debug adapter protocal),和LSP类似,可以支持多种debugger的后端,然后用统一的转换协议和client进行交互,可以自由的切换后端。

    打开文件

    sublime中的文件打开方式

    • Open (修改)
      将这个替换为 ctrl+x, ctrl+f 的默认命令,可以在quick_panel里面进行模糊过滤,但不能创建新的文件,也不能进行拼音首字母的过滤。不能进行项目文件的搜索。
      show_quick_panel 不能监听键盘事件,所以,不能做实时的输入判断和文件补全刷新。也不能监听enter或者tab的输入来判断是否创建文件。
    import sublime
    import sublime_plugin
    
    import re
    import os
    from os.path import join, dirname, abspath, isdir, basename, expanduser, exists
    
    
    class OpenBrowseCommand(sublime_plugin.TextCommand):
    
        settings_file = 'Open.sublime-settings'
    
        def show_panel(self):
            func = self.open
            elements = self.display
            sublime.set_timeout(lambda: self.view.window().show_quick_panel(elements, func), 10)
    
        def open(self, index):
            """
            If file is a directory will list the files and directories
            If file is a file will open that file
            """
            if index != -1:
                fname = self.items[index]
                if isdir(fname):
                    self.display = []
                    self.items = []
                    self.list_files(fname)
                    self.show_panel()
                elif exists(fname):
                    sublime.set_timeout(lambda: self.view.window().open_file(fname, sublime.ENCODED_POSITION), 0)
    
        def run(self, cmd):
            self.settings = sublime.load_settings(self.settings_file)
    
            self.display = []
            self.items = []
    
            # List current file (tab) directory
            fname = self.view.window().active_view().file_name()
            if self.settings.get('list_current_dir', True) and fname is not None and exists(fname):
                self.list_files(dirname(fname))
            # List bookmarks
            self.list_bookmarks()
    
            self.show_panel()
    
        def list_bookmarks(self):
            bookmarks = self.settings.get('bookmarks', list())
    
            bookmark_icon = self.settings.get('bookmark_prefix', '»')
            if bookmark_icon == '%d':
                self.display += ['%d: %s ' % (i, f) for i, f in enumerate(bookmarks)]
            else:
                self.display += [bookmark_icon + ' ' + f for f in bookmarks]
    
            bookmarks = [abspath(expanduser(f)) for f in bookmarks]
            self.items += [f for f in bookmarks]
    
        def list_files(self, fname):
            self.currentdir = fname
    
            # Parent dir
            self.display += ['..']
            self.items +=  [abspath(join(self.currentdir, os.pardir))]
    
            # List files and dirs
            self.display += [join(f, '') if isdir(join(fname, f)) else f for f in os.listdir(fname) if self.filter_files(f)]
            self.items += [join(fname, f) for f in os.listdir(fname) if self.filter_files(f)]
    
        def filter_files(self, fname):
            """
            Returns False if a file should be ignored: If the file matched any of the regular expressions
            on the settings file
            """
            fname = basename(fname)
            for regex in self.settings.get('filter_regex', list()):
                regex = regex.replace('\\\\', '\\')  # Fix backslash escaping on json
                p = re.compile(regex)
                if p.match(fname) is not None:
                    return False
            return True
    
    • OpenPath
      用于使用系统的文件管理器,如finder或者explorer打开文件夹,默认有当前文件夹和项目文件夹,我们有时想打开sublime的插件安装包所在的目录,也叫配置目录,那就可以模仿写一个方法,然后注册到Command Palette中。
    class OpenConfigFolder(sublime_plugin.WindowCommand):
      def run(self):
        if self.window.active_view() is None:
          return
    
        open_path(os.path.dirname(sublime.packages_path()))
    
      {
        "caption": "OpenPath: Open config folder",
        "command": "open_config_folder"
      }
    
    • ProjectFiles(废弃)
      自带project管理,但不方便在文件间跳转、模糊搜索和跳转. ProjectFiles已经很久没有维护了,有bug,结果经常很诡异。需要找到替代品。

    • Restart
      在开发插件的过程中,有时需要重启,直接关闭再打开,会稍显麻烦。所以,一键重启就很方便了。但是这个插件下载下来之后,在Macos中并不生效。不work就改:
      核心点在于pkill在sublime里面运行的时候不工作,替换为更底层的kill命令就可以,通过ps acx 配合awk把进程的pid找出来,关掉之后,再重新启动。

    [ IU] Restart
        restart.py
            --- Installed Packages/Restart/restart.py   2022-04-30 19:24:32
            +++ Packages/Restart/restart.py 2022-04-30 20:05:22
            @@ -14,8 +14,8 @@
                             os.execl(sys.executable,' ')
                     elif sys.platform == 'darwin':
                         #Restarting ST3 on mac
            -            if sublime.version()[:1]=='3':
            -                subprocess.call("pkill subl && "+ os.path.join(os.getcwd(), 'subl'), shell=True)
            +            if sublime.version()[:1] >= '3':
            +                subprocess.call("kill $(ps acx | awk '/sublime_text/ {print $1}') && '/Applications/Sublime Text.app/Contents/MacOS/sublime_text'", shell=True)
                         else:
                             os.execl(os.path.join(os.getcwd(), 'subl'))
                     else:
    

    自定义插件

    sublime中的几个概念

    • window(emacs中的frame)
      对应WindowCommand,可以通过sublime.active_window()获取当前的窗口,可以通过self.window.active_view()获取到view
    • pane (emacs中的window)
    • group
    • view (emacs中的buffer)
      对应TextCommand,主要的editor操作是这个这个对象里面完成的。
    • sublime 和 sublime_plugin
      sublime对外暴露的接口,主要是通过这两个模块来提供的。

    打开交互

    按键 ctrl+` ,然后可以在里面执行命令view或者window的命令: window.run_command("open_project_folder")
    如果要注册command,需要创建一个 .sublime-command的文件,并在里面添加命令:

    常用插件编写命令

    self.view.sel() # 获取光标的位置,因为sublime默认是有多鼠标操作的,所以说一个list,用[0]取第一个光标,每个光标包含起始位置,分别为a,b。是选择的顺序的起始位置,所以,a,b的大小是不确定的,和选取的顺序有关。是从前往后,还是从后往前
    self.view.size() # 获取字符的最大数量
    self.view.rowcol(self.view.size()) # 获取point的行号和列号,可以获取最大行号
    self.view.substr(sublime.Region(0, view.size())) # 可以获取所有的文档内容
    self.view.show_popup('hello'); # 这个和补全代码的弹出窗口一样,在鼠标指针那里弹出。
    sublime.message_dialog("hello") # 弹出消息窗口
    sublime.status_message('ssss') # 在左下角的status bar里面显示消息
    sublime.error_message('ssss') # 弹出错误消息窗口
    

    优化配置

    MacOS显示全路径

    在preference->settings里面添加:

    {
    	"ignored_packages":
    	[
    		"Markdown",
    		"Vintage",
    	],
    	"font_size": 13,
    	"show_full_path": true,
    	"translate_tabs_to_spaces": true,
    	"auto_complete_cycle": true,
    	"save_on_focus_lost": true,
    }
    

    项目级别的build system

    全局的python build不能添加项目的目录,可以添加项目级别的build system,这样,可以把项目的目录添加到PATHONPATH里面去。

    {
    	"folders":
    	[
    		{
    			"path": "."
    		}
    	],
    	"build_systems": [
    		{
    			"name": "StockPython",
    			"cmd": ["/usr/local/bin/python3", "-u", "$file"], 
    			"file_regex": "^[ ]*File \"(...*?)\", line ([0-9])*", 
    			"env": {"PYTHONIOENCODING": "utf8", "PYTHONPATH": "/data/stock/"},
    			"selector": "source.python",
    			"working_dir": "$project_path"
    		}
    	]
    }
    

    在sublime中编写插件,使用LSP-pyright进行python补全

    默认插件中import sublime无法识别,可以通过讲开发环境设置为 "pyright.dev_environment": "sublime_text_38" 来引入stub,这样,import sublime不会报错,可以看到函数的定义和源码。

    {
    	"folders":
    	[
    		{
    			"path": ".",
    		}
    	],
    	"settings":
    	{
    		"LSP":
    		{
    			"LSP-pyright":
    			{
    				"enabled": true,
    				"settings": {
    					"pyright.dev_environment": "sublime_text_38",
    				}
    			},
    		},
    	},
    }
    

    当有些错误提示是非必要的,可以忽略时,可以在行尾添加 # type: ignore 进行忽略。

  • 相关阅读:
    设计模式之策略模式
    整理Java面向对象
    springboot+easyui+jpa实现动态权限角色的后台管理系统(二)
    随笔9
    随笔8
    随笔7
    PHP curl方法集合
    curl json方式提交
    富文本图片和视频标签增加域名前缀
    fastadmin原生编辑按钮点击默认100%显示
  • 原文地址:https://www.cnblogs.com/yangwen0228/p/16155431.html
Copyright © 2020-2023  润新知