SublimeText Web开发在2024

随着LSP和AI发展的越来越完善,SublimeText也可通过各类插件享受到新的福利,最近尝试使用ST4(SublimeText4)作为主开发工具,体验上还是很爽的,所以想给想尝试的朋友一些推荐。

为什么不用Vscode,Jetbrains等主流IDE工具?

老实讲我感觉ST概念比较简单,很快,按钮少,但是功能上IDE肯定更全面,对新人更友善。每个人有自己在意的点,如果喜欢原先的开发工具也完全OK,目前我通过插件将ST改成了一个简略版IDE,对一些基础操作:git,sql,terminal,代码补全,定义/引用查找等功能已经集成的不错了,觉得ST是大家选择开发工具中的一个可选项。

Zed也很不错,不过还不太完善,所以感觉还等一段时间,很期待。

Plugins

插件统一通过Package Control下载即可

主题

视觉效果看着舒服是很重要的一个点,我目前尝试了:ayn,Material插件,感觉都不错,不过可能有些小细节,希望能自定义一下,比如注释代码的颜色,侧边栏字体大小,滚动块儿样式等等。

可以通过PackageResourceViewer插件,快速定位到插件样式定义文件,然后去修改

Git

  1. Git 插件
  2. GitGutter 插件
  3. Sublime Merge 软件

通过Git,GitGutter可以很方便在写代码时操作Git,不过有时候遇到代码冲突,分支管理等操作还是不太方便,通过Sublime Merge可以无缝衔接增强。

命令行

  1. Terminus

可以通过绑定快捷键,快速打开命令行,但是我发现ST中的Panel默认只能打开一个Shell。通过指定不同的panel_name解决这个问题:

{
   "keys": [
      "alt+1"
   ],
   "command": "toggle_terminus_panel",
   "args": {
      "panel_name": "first-panel"
   },
},
{
   "keys": [
      "alt+2"
   ],
   "command": "toggle_terminus_panel",
   "args": {
      "panel_name": "second-panel"
   },
},

这样就可以通过快捷键,切换到不同的shell中了。

SQL

  1. SQLTools 插件

操作SQL的瑞士军刀,真的超级好用,提供SQL编写字段,表等补全功能,不过由于项目中没有sql文件,每次创建删除又很麻烦,需要注意ST原生的宏记录,对于创建新文件页面无效,我通过Multicommand插件,来编写宏:

// query_file.sublime-macro
{
    "cmd": ["new_file", "untitled.sql"],
    "args": {"syntax": "SQL"},
    "flags": ["window"]
}

文件操作

  1. AdvancedNewFile 快速创建文件
  2. Quick File Creator 快速指定目录创建文件
  3. SyncedSideBar ST在文件切换时,侧边文件导航栏并不会定位到当前文件,通过该插件可以自动定位
  4. Local History 记录本地代码修改记录

AI代码补全

  1. Codeium

配置简单,响应快速,智商还算在线,官网上说比Copilot强,个人免费。

LSP

  1.     "LSP"
    
  2.     "LSP-css"    
    
  3.     "LSP-eslint",    
    
  4.     "LSP-json",
    
  5.     "LSP-typescript",
    
  6.     "LSP-volar"
    

目前写Ruby用的LSP是solargraph,可以看文档自己去配置就好,sublime-lsp。再说一遍LSP真香!!!

配置同步

  1. Sync Settings

就是说在笔记本上ST的配置,想同步到台式机上,就可以通过该插件将配置同步到:gist.github.com


这一套下来,就基本上差不多了,像前端开发也会用Emmet插件,不过最近发现在写Vue时,常量的定义查找,标签组件的定义查找,都没用,只能通过文件名搜索查看,感觉还是不太方便,目前仍在找解决方案。

可以看出ST仍有一些不便之处,所以就得视情况而定去选择工具。为了某些优势,能容纳其他的问题。

插件开发

通过命令行中:View Package File能快速找到你定义的插件或者第三方插件代码

推荐教程:bilibili

基础概念

import sublime  # 全局对象,和js中的window类似
import sublime_plugin
  1. sublime.Window类:对应就是操作窗口
  2. sublime.Sheet类:对应就是窗口中一个个编辑页
  3. sublime.View类:对应编辑页中的文本内容

可以创建多个window

一个窗口可以有多个Sheet

一个Sheet只有一个View,但不一定是View,可能打开的是图片之类的

一般我们写插件时,会遇到:

  1. sublime_plugin.TextCommand 操作文本的
  2. sublime_plugin.WindowCommand 操作页面的

一个Window下可以有多个group(分屏),group就类似于分组,将页面分割为独立的组,每个group都可以拥有独立的sheet 和 view,

正则查询

import sublime
import sublime_plugin
import re

class SearchRegexCommand(sublime_plugin.WindowCommand):
    def run(self):
        # Show input panel to get user input
        self.window.show_input_panel("Enter text (A.B):", "", self.on_done, None, None)

    def on_done(self, user_input):
        parts = user_input.split('.')
        if len(parts) != 2:
            sublime.error_message("Input should contain exactly one '.'")
            return

        a, b = parts
        # Define the regex pattern
        pattern = rf"\s{re.escape(a)}:\s*\{{[^}}]*?{re.escape(b)}:"
        # Perform global search
        self.window.run_command('show_panel', {'panel': 'find_in_files', 'regex': True, 'scope': 'project'})
        sublime.active_window().run_command('insert_snippet', {'contents': pattern})
  1. 通过快捷键生成一个输入框,用户可进行输入
  2. 将用户输入通过 . 进行分割,要求必须是A.B格式
  3. 生成正则表达式
  4. 页面展示文件查询表格
  5. 将生成好的正则表达式,插入到表格中
  6. 用户回车可查询

查找常量

import sublime
import sublime_plugin

# 获取view中选中的文本
def getSel(view):
	# 获取选中区域
	sel = view.sel()
	# 获取选中内容
	reg = sel[0]
	# 获取选中内容
	sels = view.substr(reg)
	if sels == "":
		reg = sublime.Region(0, view.size())
		sels = view.substr(reg)
	# reg: 选中的区域, sels: 选中的内容
	return reg, sels

class FindConstCommand(sublime_plugin.TextCommand):
	def run(self, edit):
		reg, sels = getSel(self.view)
		if not sels:
			return
		segments = sels.split('.')
		file_name = "src/util/constants.js"

		target_view = self.view.window().new_file()
		target_view.set_name("常量查询文件")
		target_view.set_scratch(True)
		target_view = self.view.window().open_file(file_name, sublime.TRANSIENT)
		sublime.set_timeout_async(lambda: self.on_file_opened(target_view,segments), 2)

	def on_file_opened(self,target_view,segments):
		pattern = rf"constants.*{segments[0].lower()}\.js"
		flags = 0
		matches = target_view.find_all(pattern, flags)

		region = matches[0]
		start = region.begin()
		end = region.end() 
		matched_text = target_view.substr(region)

		if matches:
			file_name = "src/util/" + matched_text
			new_view = self.view.window().open_file(file_name, sublime.TRANSIENT)
			sublime.set_timeout_async(lambda: self.on_certain_file_opened(new_view,segments), 2)

	def on_certain_file_opened(self,target_view,segments):
		flags = 0
		if len(segments) == 3:
			pattern = rf"{segments[1]}:[\s\S]*?{segments[2]}:"
		else:
			pattern = rf"{segments[1]}:"
		matches = target_view.find_all(pattern, flags)
		if matches:
			target_view.sel().clear()
			target_view.sel().add(matches[0])
			target_view.show_at_center(matches[0])

切换组

Key binning

{ 
  "keys": ["super+alt+up"], 
  "command": "new_pane"
},
{
  "keys": ["ctrl+shift+left"],
  "command": "change_group",
  "args": {
    "left": true
  }
},
{
  "keys": ["ctrl+shift+right"],
  "command": "change_group",
  "args": {
    "right": true
  }
},

Plugin

import sublime
import sublime_plugin


class ChangeGroupCommand(sublime_plugin.WindowCommand):
    def run(self,**kwargs):
        # self.window.show_input_panel("Enter text (A.B):", "", self.on_done, None, None)
        group_size = self.window.num_groups()
        current_group = self.window.active_group()

        left = kwargs.get('left', False)
        right = kwargs.get('right', False)

        if left:
            if current_group == 0:
                self.window.focus_group(group_size - 1)
            else:
                self.window.focus_group(current_group - 1)
        else:
            self.window.focus_group(current_group - 1)

        if right:
            self.window.focus_group(0) if current_group == (group_size - 1) else self.window.focus_group(current_group + 1)

允许在Command Palette中搜索

import sublime
import sublime_plugin


class ExampleCommand(sublime_plugin.TextCommand):
	def run(self, edit):
		self.view.insert(edit, 0, "Hello, World!")

# 在自己编写的插件下声明即可
ExampleCommand.sublime_command_class = ExampleCommand

构建系统

相关优秀视频教程

  1. youtube1
  2. youtube2

mac中默认cmd+b会对当前页面进行构建执行,我们也可以自己写一个构建系统,比如我想快速对项目跑一个测试,或者快速执行rails c进行页面交互,等等类似的操作都可以通过构建系统完成。

而Sublime默认的构建系统是不支持交互的,通过Package:Terminus可以优化为一个可交互的构建系统

在开发前建议下载包:PackageDev(开发插件,构建系统提供自动补全,语义高亮)``Origami(提供页面切割功能)

执行shell命令

{
    "shell_cmd": "docker exec ruby_dev sh -c \"cd /app/algorithm && rake test\"",
    "file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
}

shell_cmd: 执行shell操作

file_rege:构建结果中如果有代码信息可以进行跳转

这是系统默认自带的

使用Terminus优化

{
    "target": "terminus_exec",
    "cancel": "terminus_cancel_build",
    "focus": true,  
    "shell_cmd": "docker exec ruby_dev sh -c \"cd /app/algorithm && rake test\"",
    "file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
}

target: 表示告诉Sublime这个构建系统比较特殊,通过Terminus执行

cancel:如果构建时间过长,可以进行取消

focus: 自动聚焦到控制台

timeit:展示构建时间,false:就可以不展示

构建执行rails s / rails c

{
    "target": "terminus_exec",
    "cancel": "terminus_cancel_build",
    "focus": true,  
    "shell_cmd": "./bin/rails c", // rails s
    "working_dir": "$project_path",
    "file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$", // 这里的正则还需要调整
}

结尾

上述内容很多概念其实每个编辑器都是通用的,重要的是当我们理解这些概念时,我们可以根据我们的开发习惯,优化编辑器行为,提高我们的开发效率。比如我会借鉴一些Jetbrain好用的快捷键和指令,看能不能放到ST上,然后把ST上一些用着舒服的内容,尝试放到Jetbrain上。