v0.1.0-b218 (alpha) · Apple Silicon · macOS 13.2+ · 更新日志
22960 # EditorContainer : _on_tab_label_clicked
22961 @func_trace
22962 def _on_tab_label_clicked(self):
22963 editor = ensure_not_deleted(self.main_editor.editor)
22964 if editor is not None:
22965 safe_focus(editor)
22966
22967 # EditorContainer : _on_tab_label_toggle
22968 @func_trace
22969 def _on_tab_label_toggle(self):
22970 window = ensure_not_deleted(self.window)
22971 if window is None:
22972 return
22973
22974 buffer = self.buffer
22975 if buffer is None:
22976 return
22977
22978 window.buffer_manager.toggle_active(buffer)
22979
22980 # EditorContainer : _on_tab_label_exclusive
22981 @func_trace
22982 def _on_tab_label_exclusive(self):
22983 window = ensure_not_deleted(self.window)
22984 if window is None:
22985 return
22986
22987 buffer = self.buffer
22988 if buffer is None:
22989 return
22990
22991 window.buffer_manager.set_as_active_tab(buffer)
22992
22993 # EditorContainer : _file_changed
22994 @func_trace
22995 def _file_changed(self, *_): [97 lines folded]
23093
23094 # EditorContainer : _do_after_file_changed
23095 @func_trace
23096 def _do_after_file_changed(self): [5 lines folded]
10373 directory = os.path.dirname(path) or "."
10374 tmp_path = None
10375
10376 os.makedirs(directory, exist_ok=True)
10377
10378 fd, tmp_path = tempfile.mkstemp(dir=directory, prefix=".tmp_")
10379
10380 try:
10381 with os.fdopen(fd, "w", encoding="utf-8") as f:
10382 f.write(text)
10383 f.flush()
10384 os.fsync(f.fileno())
10385
10386 os.replace(tmp_path, path)
10387 tmp_path = None
10388
10389 finally:
10390 if tmp_path is not None:
10391 try:
10392 os.remove(tmp_path)
10393 except OSError:
10394 pass
10395
10396 # CodeEditor : _save_file
10397 # @func_trace
10398 def _save_file(self): [113 lines folded]
10512
10513 # CodeEditor : _save_shadow_file
10514 @func_trace
10515 def _save_shadow_file(self): [18 lines folded]
10534
10535 # CodeEditor : save_file_as
10536 @plugin_api
10537 @command("Save file as...")
10538 def save_file_as(self): [20 lines folded]
10559
10560 # CodeEditor : save_file_copy_as
10561 @plugin_api
10562 @command("Save copy of file as...")
10563 def save_file_copy_as(self): [20 lines folded]
Peeknext 基于原生 C++ 编辑核心构建,将响应速度视为设计约束,而不是事后添加的优化。
即使文件不断增大,编辑依然保持流畅。同一文档的多个视图共享底层缓冲区。
我们使用真实源代码文件测试性能,并发布可复现的基准测试结果。
View features → 267 // enter new state
268
269 if (sc.state == SCE_HACK_DEFAULT) {
270 // numbers
271 if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
272 sc.SetState(SCE_HACK_NUMBER);
273 }
274 // identifiers
275 else if (!sc.atLineEnd && (setWordStart.Contains(sc.ch) || (sc.ch == '@'))) {
276 sc.SetState(State_Identifier);
277 }
278 // block comment
279 else if (sc.Match('/', '*')) {
280 sc.SetState(State_BlockComment);
281 sc.Forward();
282 }
283 // line comments
284 else if (sc.Match('/', '/')) {
285 sc.SetState(State_LineComment);
286 }
287 // strings
288 else if (sc.ch == '\"') {
289 sc.SetState(SCE_HACK_STRING);
290 isIncludePreprocessor = false;
291 }
292 // includes
293 else if (isIncludePreprocessor && sc.ch == '<') {
294 sc.SetState(SCE_HACK_STRING);
295 }
296 // characters
297 else if (sc.ch == '\'') {
298 sc.SetState(State_Character);
实测数据,而非空口宣称
16.6 ms
在 753,821 行源代码文件上测得的 P95 输入延迟。
20M lines
已测试的最大语法高亮文件。
698 MB
处理 500 万行源代码文件时的内存占用。
15 types
16 int
17 float
18 arguments
19 out : stdin to use previous output as input
20 : stdout to print
21 """
22
23 program = """
24 Module add 1 2 3 type=float out=stdin
25 Module sub stdin 1 2 type=int out=stdout
26 """
27
28 # Module definition
29 class Module:
30
31 # Add function
32 def add(*args, **kwargs):
33 type_ = globals()["__builtins__"].getattr(globals()["__builtins__"], kwargs["type"])
34
35
36 # Sub function
37 def sub(*args, **kwargs):
38 type_ = globals()["__builtins__"].getattr(globals()["__builtins__"], kwargs["type"])
39 return float(args[0]) if type_ == 'float' else int(args[0]) - sum(map(type_, args[1:]))
40
41 def get_args(tokens, STDIN): [18 lines folded]
60
61 def interpret(program): [25 lines folded]
87
88 interpret(program) # 3
89
无需将代码发送到其他地方,也能使用实用功能。Peeknext 直接处理本地文件、本地索引和本地模型。
上下文感知自动补全基于当前文件构建,无需语言服务器。AI 功能通过 Ollama 在本地运行,默认关闭。
文件始终保存在你的设备上,编辑器在完全离线时也能正常工作。
View features →隐私融入设计
无遥测或跟踪。无后台下载。甚至没有自动更新程序。
无需开启离线模式。
Peeknext 向 Python 开放编辑器命令,让重复性工作直接融入编辑器,无需额外插件或外部工具。
编写普通 Python 函数,将其注册为命令并分配快捷键,像使用内置命令一样使用它们。
内联命令将同样的能力带入文档:无需离开编辑器,即可运行 Shell 命令、求值 Python 或使用 AI。
View features → 9 ////////////////////////` Resolution: 3440x1440
10 -+++++++++++++++++++++++` DE: Aqua
11 /++++++++++++++++++++++/ WM: Quartz Compositor
12 /sssssssssssssssssssssss. WM Theme: Graphite (Dark)
13 :ssssssssssssssssssssssss- Font: MenloRegular
14 osssssssssssssssssssssssso/` Disk: 375G / 494G (83%)
15 `syyyyyyyyyyyyyyyyyyyyyyyy+` CPU: Apple M2 Pro
16 `ossssssssssssssssssssss/ GPU: Apple M2 Pro
17 :ooooooooooooooooooo+. RAM: 1914MiB / 16384MiB
18 `:+oo+/:-..-:/+o+/-
19
20 % git log --oneline -5
21 7e43c91 Fix stale index results after file changes
22 20b9ad4 Add PHP symbols to file outline
23 e3816fc Preserve cursor position when reopening files
24 9ad0c72 Reduce allocations while indexing large files
25 615bc84 Fix split view restoring the wrong document
26
27 > Summarize these changes for the changelog.
## Editor
- Added PHP symbols to the file outline.
- Cursor position is now preserved when reopening files.
- Fixed split views occasionally restoring the wrong document.
## Performance and reliability
- Reduced memory allocations while indexing large files.
- Fixed stale autocomplete results after files changed on disk.
1 2 # This is the default scripts-file for Peeknext 3 4 @command("Word count") 5 def word_count(): 6 import re 7 8 text = selected_text() 9 count = len(re.findall(r"\b[\w'-]+\b", text)) 10 11 message (f"Word count: {count:,} words") 12 13 @command("Insert UUID") 14 def insert_uuid(): [2 lines folded] 17 18 @command("Markdown: Selection to link") 19 def insert_link(): [2 lines folded] 22 23 @command("Markdown: Insert unchecked box") 24 def insert_unchecked_box(): [1 lines folded] 26 27 @command("Markdown: Wrap selection in fenced block") 28 def fenced_block(): [2 lines folded] 31 32 @command("Markdown: Bold") 33 def make_bold(): 34 text = selected_text() 35 insert_text(text=f"**{text}**") 36 37 38 39
Zero-latency typing
Peeknext maintains a measured P95 typing latency of 17.86 ms while editing a 1 million-line Odin source file with syntax highlighting enabled.
Local AI, on your Mac
Peeknext works directly with local Ollama models, with no account, telemetry, or cloud intermediary. Use local code completion and inline AI while keeping your code and inference on your Mac.
Native macOS code editors
A look at code editors built specifically for macOS, from long-running editors like BBEdit and TextMate to newer alternatives like Nova, CodeEdit, and Peeknext.
Plain text note taking
Keep notes as ordinary Markdown, plain text, Org Mode, or other files. Open directly into your notes folder, search with ripgrep, and organize everything without a proprietary database.
许可证常见问题
非商业用途免费。商业用途需要购买许可证。
为什么需要购买许可证?
Peeknext 可免费用于非商业用途。如果用于工作,则需要商业许可证。这也是产品持续开发的资金来源。
为什么需要购买许可证?
Peeknext 可免费用于非商业用途。如果用于工作,则需要商业许可证。这也是产品持续开发的资金来源。
为什么需要购买许可证?
Peeknext 可免费用于非商业用途。如果用于工作,则需要商业许可证。这也是产品持续开发的资金来源。
为什么需要购买许可证?
Peeknext 可免费用于非商业用途。如果用于工作,则需要商业许可证。这也是产品持续开发的资金来源。
为什么需要购买许可证?
Peeknext 可免费用于非商业用途。如果用于工作,则需要商业许可证。这也是产品持续开发的资金来源。
为什么需要购买许可证?
Peeknext 可免费用于非商业用途。如果用于工作,则需要商业许可证。这也是产品持续开发的资金来源。
为什么需要购买许可证?
Peeknext 可免费用于非商业用途。如果用于工作,则需要商业许可证。这也是产品持续开发的资金来源。
为什么需要购买许可证?
Peeknext 可免费用于非商业用途。如果用于工作,则需要商业许可证。这也是产品持续开发的资金来源。
我们目前正在开发和规划的功能。
File preview in file explorer
Writer mode with focused interface
Variable fonts and wikilinks
Faster search in very large files
One command palette for all dialogs
精心调校的原生词法分析器,提供快速、精确的语法高亮。
Minimal syntax highlighting for better performance. The lexers are written in C++ and optimized for speed.
Code folding is syntax-aware, allowing for language-specific behavior.
Some languages have file outline support, enabling navigation through the code via symbols.
Asm
Bash
C
CSS
Clojure
C++
D
Diff
Elixir
Fortran
Gleam
Go
Haskell
HTML
Jai
Java
JavaScript
Julia
JSON
LaTeX
Lua
Makefile
Markdown
MATLAB
Mojo
Nim
OCaml
Odin
Org
Pascal
Perl
PHP
Python
R
Ruby
Rust
SQL
Swift
TOML
TypeScript
Typst
WAT
YAML
Zig
Koi is now Peeknext
Koi Editor and Hackerman are now Peeknext, with a shared name and visual identity.
Debugging race condition that was actually a lifetime bug
A random QThread crash looked like a race condition, but turned out to be an orphaned editor buffer and delayed garbage collection.
Next steps for navigation
Rethinking editor navigation around lightweight histories, on-demand search, and local structure.