体验 Helix 编辑器

最近发现了一个用 Rust 写的 Vim-like 编辑器 Helix,用有强大的性能和各种开箱即用的功能。经过短暂时间的体验,我认为 Helix 已经可以在大部分领域替代 Vim/Neovim/VS Code。 性能 作为一款用 Rust 写的编辑器,Helix 自然拥有优异的性能。得益于其丰富的内置功能,Helix 无需插件就可以完成许多 Vim 只能用插件做到的事,并且还通过 Rust 获得了性能上的优势。现在我的 Neovim 安装有 coc.nvim、vim-visual-multi 等插件,共十个,启动需要延迟近 0.5 秒,虽然已经显著快于 VS Code,但相比 Helix 的小于 0.1 秒,还是稍显逊色。(当然这可能与我现在用的是 Windows 有关) 虽然现在(2023年4月8日)Helix 还没有插件系统,但未来的插件系统大概率会用 WASM 实现,相比 Vim Script 以及 Neovim 用的 Lua 等脚本语言会更快。 编辑体验 整体思路 首先 Helix 和 Vim 一样都是模态编辑器,具有多种模式,最基本的操作思路是一样的,比如都使用 hjkl 进行移动,都使用 i、a 等进行插入,都使用 y,d、p 进行复制删除粘贴。但是 Helix 采用了 selection -> action 模式,比如向右删除 3 个字符需要按 3ld 而不是 d3l,先选择在操作,就我个人而言,这种方式确实更舒适。 另外,Helix 的命令有丰富的提示,而且还可以通过 <space> ? 打开命令面板查找命令,并带有相关键位提示,包括自定义的键位。 ...

April 8, 2023 · 5 min · Justin Chen

用 Rust 开发 Brainfuck 解释器

项目地址:https://github.com/StarryReverie/brainfuck-interpreter Brainfuck 是什么就不具体介绍了,可以看这里。以下简称 bf。 这个解释器实现总体上是比较简单的,但是相比其他的大多数解释器还是有比较多的不同之处,具体如下: 更多的配置选项 内存的长度与地址范围:可配置为负数 单个内存单元的数据类型 数据溢出处理机制:wrap 或错误 读到 EOF 的处理机制:返回 0、EOF 本身或不改变 优化指令 采用类似编译为字节码的机制 这个项目可以算是学习 Rust 的练手项目,尝试着用了如 clap 这样的 crate。接下来就介绍一些技术细节。 使用方法 具体说明在项目 README. 编译、安装、执行全过程: $ git clone https://github.com/StarryReverie/brainfuck-interpreter.git $ cd brainfuck-interpreter $ cargo install --path ./crates/bf-exec # The program will be installed to ~/.cargo/bin $ bf-exec ./examples/helloworld.bf Hello World! ./examples/helloworld.bf: ++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>. 实现原理 目前,项目分为两个 crate:common 与 bf-exec,其中 common 实现了解释器的所有逻辑,而 bf-exec 是 common 的前端,负责处理输入和配置。 common 的模块树如下: compiler:解析代码并转换为 IR (Intermediate Representation,中间表示) lexer:词法分析 parser:语法分析并优化,生成 AST SyntaxTree syntax:AST 生成 optimizer:AST 优化 instruction:根据 AST 生成 IR,同时也是最终执行的指令 execution:IR 的执行与相关环境 memory:按照 bf 的内存模型实现的可配置内存 strategy:基于策略模式实现的可配置组件 config:构建 Memory 的配置 stream:bf 的 IO 实现 config:构建 InStream、OutStream 的配置 context:Memory 与 InStream、OutStream 的组合 processor:运行指令,并调用 Context 实现细节 代码优化 同质代码合并 首先最简单的就是这个优化,它是指把相邻的 + 与 -、< 与 > 合并到一起并加上一个重复次数。 ...

January 26, 2023 · 7 min · Justin Chen

Python 网络爬虫获取 SYZOJ AC 代码

写本文之前,我共有两百多道题目在校内 OJ 上通过,由于某些原因,想要保存这些代码,于是想到使用 Python 实现自动爬取代码。同时考虑到效率问题,决定使用 aiohttp 编写一个高性能异步爬虫。 实现目标分析 这个爬虫需要能够爬取所有的已通过题目的列表,并继续爬取这些已通过题目的代码,随后保存到文件中。 校内 OJ 基于 SYZOJ 搭建,该 OJ 的项目地址为 https://github.com/syzoj/syzoj,故接下来的代码都是基于其实现的。 由于这个 OJ 的外网域名的带宽很小,一个网页最坏情况下需要花费 2~3 秒的时间,所以必须采用异步实现。这里就使用 aiohttp 了。 获取 Cookie 由于直接从浏览器里获取的 Cookie 无法正常使用,传给服务器无法识别,猜测是编码问题,所以使用在爬虫运行时即时获取 Cookie 的办法。 分析 SYZOJ 的登陆页面源码,找到如下代码片段: function login() { password = md5($("#password").val() + "syzoj2_xxx"); $("#login").addClass("loading"); $.ajax({ url: "/api/login", type: 'POST', data: { "username": $("#username").val(), "password": password }, async: true, success: function(data) { error_code = data.error_code; switch (error_code) { case 1001: show_error("用户不存在"); break; case 1002: show_error("密码错误"); break; case 1003: show_error("您尚未设置密码,请通过下方「找回密码」来设置您的密码。"); break; case 1: success(data.session_id); return; default: show_error("未知错误"); break; } $("#login").text("登录"); $("#login").removeClass("loading"); }, error: function(XMLHttpRequest, textStatus, errorThrown) { alert(XMLHttpRequest.responseText); show_error("未知错误"); $("#login").text("登录"); } }); } 可以发现,SYZOJ 通过 /api/login 这个 Web API 发送请求获取 Cookie,使用 POST 方法,数据为 username 和 password,分别为用户名和密码加上 syzoj2_xxx 这个 salt 的 MD5,所以可以使用以下 Python 代码获取 Cookie ...

April 18, 2022 · 4 min · Justin Chen