bunmicro 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. package/LICENSE +22 -0
  2. package/PORTING.md +34 -0
  3. package/README.md +153 -0
  4. package/bmi +5 -0
  5. package/bun.lock +17 -0
  6. package/bunmicro +5 -0
  7. package/hlw.md +5 -0
  8. package/package.json +18 -0
  9. package/runtime/colorschemes/atom-dark.micro +33 -0
  10. package/runtime/colorschemes/bubblegum.micro +31 -0
  11. package/runtime/colorschemes/cmc-16.micro +47 -0
  12. package/runtime/colorschemes/cmc-tc.micro +43 -0
  13. package/runtime/colorschemes/darcula.micro +34 -0
  14. package/runtime/colorschemes/default.micro +1 -0
  15. package/runtime/colorschemes/dracula-tc.micro +49 -0
  16. package/runtime/colorschemes/dukedark-tc.micro +38 -0
  17. package/runtime/colorschemes/dukelight-tc.micro +38 -0
  18. package/runtime/colorschemes/dukeubuntu-tc.micro +38 -0
  19. package/runtime/colorschemes/geany.micro +29 -0
  20. package/runtime/colorschemes/gotham.micro +29 -0
  21. package/runtime/colorschemes/gruvbox-tc.micro +29 -0
  22. package/runtime/colorschemes/gruvbox.micro +26 -0
  23. package/runtime/colorschemes/material-tc.micro +36 -0
  24. package/runtime/colorschemes/monokai-dark.micro +28 -0
  25. package/runtime/colorschemes/monokai.micro +34 -0
  26. package/runtime/colorschemes/one-dark.micro +39 -0
  27. package/runtime/colorschemes/railscast.micro +37 -0
  28. package/runtime/colorschemes/simple.micro +33 -0
  29. package/runtime/colorschemes/solarized-tc.micro +31 -0
  30. package/runtime/colorschemes/solarized.micro +30 -0
  31. package/runtime/colorschemes/sunny-day.micro +29 -0
  32. package/runtime/colorschemes/twilight.micro +40 -0
  33. package/runtime/colorschemes/zenburn.micro +30 -0
  34. package/runtime/help/actions.md +161 -0
  35. package/runtime/help/colors.md +421 -0
  36. package/runtime/help/commands.md +161 -0
  37. package/runtime/help/copypaste.md +149 -0
  38. package/runtime/help/defaultkeys.md +141 -0
  39. package/runtime/help/help.md +63 -0
  40. package/runtime/help/keybindings.md +760 -0
  41. package/runtime/help/linter.md +90 -0
  42. package/runtime/help/options.md +701 -0
  43. package/runtime/help/plugins.md +544 -0
  44. package/runtime/help/tutorial.md +112 -0
  45. package/runtime/jsplugins/chapter/chapter.js +108 -0
  46. package/runtime/jsplugins/diff/diff.js +46 -0
  47. package/runtime/jsplugins/example/example.js +108 -0
  48. package/runtime/jsplugins/linter/linter.js +281 -0
  49. package/runtime/plugins/autoclose/autoclose.lua +75 -0
  50. package/runtime/plugins/ftoptions/ftoptions.lua +17 -0
  51. package/runtime/plugins/literate/README.md +5 -0
  52. package/runtime/plugins/literate/literate.lua +55 -0
  53. package/runtime/plugins/status/help/status.md +21 -0
  54. package/runtime/plugins/status/status.lua +62 -0
  55. package/runtime/syntax/LICENSE +22 -0
  56. package/runtime/syntax/PowerShell.yaml +128 -0
  57. package/runtime/syntax/README.md +63 -0
  58. package/runtime/syntax/ada.yaml +43 -0
  59. package/runtime/syntax/apacheconf.yaml +59 -0
  60. package/runtime/syntax/arduino.yaml +101 -0
  61. package/runtime/syntax/asciidoc.yaml +51 -0
  62. package/runtime/syntax/asm.yaml +123 -0
  63. package/runtime/syntax/ats.yaml +99 -0
  64. package/runtime/syntax/awk.yaml +44 -0
  65. package/runtime/syntax/b.yaml +87 -0
  66. package/runtime/syntax/bat.yaml +57 -0
  67. package/runtime/syntax/c.yaml +60 -0
  68. package/runtime/syntax/caddyfile.yaml +23 -0
  69. package/runtime/syntax/cake.yaml +7 -0
  70. package/runtime/syntax/clojure.yaml +38 -0
  71. package/runtime/syntax/cmake.yaml +42 -0
  72. package/runtime/syntax/coffeescript.yaml +56 -0
  73. package/runtime/syntax/colortest.yaml +19 -0
  74. package/runtime/syntax/conky.yaml +17 -0
  75. package/runtime/syntax/cpp.yaml +91 -0
  76. package/runtime/syntax/crontab.yaml +36 -0
  77. package/runtime/syntax/crystal.yaml +72 -0
  78. package/runtime/syntax/csharp.yaml +52 -0
  79. package/runtime/syntax/css.yaml +44 -0
  80. package/runtime/syntax/csx.yaml +8 -0
  81. package/runtime/syntax/cuda.yaml +68 -0
  82. package/runtime/syntax/cython.yaml +52 -0
  83. package/runtime/syntax/d.yaml +121 -0
  84. package/runtime/syntax/dart.yaml +46 -0
  85. package/runtime/syntax/default.yaml +10 -0
  86. package/runtime/syntax/dockerfile.yaml +36 -0
  87. package/runtime/syntax/dot.yaml +29 -0
  88. package/runtime/syntax/elixir.yaml +30 -0
  89. package/runtime/syntax/elm.yaml +38 -0
  90. package/runtime/syntax/erb.yaml +42 -0
  91. package/runtime/syntax/erlang.yaml +45 -0
  92. package/runtime/syntax/fish.yaml +48 -0
  93. package/runtime/syntax/forth.yaml +34 -0
  94. package/runtime/syntax/fortran.yaml +64 -0
  95. package/runtime/syntax/freebsd-kernel.yaml +14 -0
  96. package/runtime/syntax/fsharp.yaml +48 -0
  97. package/runtime/syntax/gdscript.yaml +61 -0
  98. package/runtime/syntax/gemini.yaml +19 -0
  99. package/runtime/syntax/gentoo-ebuild.yaml +48 -0
  100. package/runtime/syntax/gentoo-etc-portage.yaml +23 -0
  101. package/runtime/syntax/git-commit.yaml +35 -0
  102. package/runtime/syntax/git-config.yaml +14 -0
  103. package/runtime/syntax/git-rebase-todo.yaml +19 -0
  104. package/runtime/syntax/gleam.yaml +69 -0
  105. package/runtime/syntax/glsl.yaml +26 -0
  106. package/runtime/syntax/gnuplot.yaml +15 -0
  107. package/runtime/syntax/go.yaml +62 -0
  108. package/runtime/syntax/godoc.yaml +17 -0
  109. package/runtime/syntax/golo.yaml +73 -0
  110. package/runtime/syntax/gomod.yaml +31 -0
  111. package/runtime/syntax/graphql.yaml +47 -0
  112. package/runtime/syntax/groff.yaml +30 -0
  113. package/runtime/syntax/groovy.yaml +111 -0
  114. package/runtime/syntax/haml.yaml +16 -0
  115. package/runtime/syntax/hare.yaml +52 -0
  116. package/runtime/syntax/haskell.yaml +52 -0
  117. package/runtime/syntax/hc.yaml +52 -0
  118. package/runtime/syntax/html.yaml +70 -0
  119. package/runtime/syntax/html4.yaml +25 -0
  120. package/runtime/syntax/html5.yaml +25 -0
  121. package/runtime/syntax/ini.yaml +23 -0
  122. package/runtime/syntax/inputrc.yaml +14 -0
  123. package/runtime/syntax/java.yaml +37 -0
  124. package/runtime/syntax/javascript.yaml +76 -0
  125. package/runtime/syntax/jinja2.yaml +19 -0
  126. package/runtime/syntax/json.yaml +39 -0
  127. package/runtime/syntax/jsonnet.yaml +92 -0
  128. package/runtime/syntax/julia.yaml +57 -0
  129. package/runtime/syntax/justfile.yaml +40 -0
  130. package/runtime/syntax/keymap.yaml +27 -0
  131. package/runtime/syntax/kickstart.yaml +16 -0
  132. package/runtime/syntax/kotlin.yaml +66 -0
  133. package/runtime/syntax/kvlang.yaml +67 -0
  134. package/runtime/syntax/ledger.yaml +14 -0
  135. package/runtime/syntax/lfe.yaml +17 -0
  136. package/runtime/syntax/lilypond.yaml +26 -0
  137. package/runtime/syntax/lisp.yaml +17 -0
  138. package/runtime/syntax/log.yaml +92 -0
  139. package/runtime/syntax/lua.yaml +111 -0
  140. package/runtime/syntax/mail.yaml +25 -0
  141. package/runtime/syntax/makefile.yaml +38 -0
  142. package/runtime/syntax/man.yaml +12 -0
  143. package/runtime/syntax/markdown.yaml +49 -0
  144. package/runtime/syntax/mc.yaml +23 -0
  145. package/runtime/syntax/meson.yaml +51 -0
  146. package/runtime/syntax/micro.yaml +34 -0
  147. package/runtime/syntax/mpdconf.yaml +13 -0
  148. package/runtime/syntax/msbuild.yaml +6 -0
  149. package/runtime/syntax/nanorc.yaml +16 -0
  150. package/runtime/syntax/nftables.yaml +30 -0
  151. package/runtime/syntax/nginx.yaml +22 -0
  152. package/runtime/syntax/nim.yaml +27 -0
  153. package/runtime/syntax/nix.yaml +32 -0
  154. package/runtime/syntax/nu.yaml +114 -0
  155. package/runtime/syntax/objc.yaml +60 -0
  156. package/runtime/syntax/ocaml.yaml +43 -0
  157. package/runtime/syntax/octave.yaml +83 -0
  158. package/runtime/syntax/odin.yaml +64 -0
  159. package/runtime/syntax/pascal.yaml +45 -0
  160. package/runtime/syntax/patch.yaml +14 -0
  161. package/runtime/syntax/peg.yaml +16 -0
  162. package/runtime/syntax/perl.yaml +58 -0
  163. package/runtime/syntax/php.yaml +60 -0
  164. package/runtime/syntax/pkg-config.yaml +12 -0
  165. package/runtime/syntax/po.yaml +12 -0
  166. package/runtime/syntax/pony.yaml +37 -0
  167. package/runtime/syntax/pov.yaml +21 -0
  168. package/runtime/syntax/privoxy-action.yaml +14 -0
  169. package/runtime/syntax/privoxy-config.yaml +10 -0
  170. package/runtime/syntax/privoxy-filter.yaml +12 -0
  171. package/runtime/syntax/proto.yaml +40 -0
  172. package/runtime/syntax/prql.yaml +84 -0
  173. package/runtime/syntax/puppet.yaml +22 -0
  174. package/runtime/syntax/python2.yaml +60 -0
  175. package/runtime/syntax/python3.yaml +62 -0
  176. package/runtime/syntax/r.yaml +32 -0
  177. package/runtime/syntax/raku.yaml +42 -0
  178. package/runtime/syntax/reST.yaml +18 -0
  179. package/runtime/syntax/renpy.yaml +15 -0
  180. package/runtime/syntax/rpmspec.yaml +43 -0
  181. package/runtime/syntax/ruby.yaml +73 -0
  182. package/runtime/syntax/rust.yaml +78 -0
  183. package/runtime/syntax/sage.yaml +60 -0
  184. package/runtime/syntax/scad.yaml +53 -0
  185. package/runtime/syntax/scala.yaml +33 -0
  186. package/runtime/syntax/sed.yaml +13 -0
  187. package/runtime/syntax/sh.yaml +69 -0
  188. package/runtime/syntax/sls.yaml +15 -0
  189. package/runtime/syntax/smalltalk.yaml +55 -0
  190. package/runtime/syntax/solidity.yaml +41 -0
  191. package/runtime/syntax/sql.yaml +35 -0
  192. package/runtime/syntax/stata.yaml +67 -0
  193. package/runtime/syntax/svelte.yaml +27 -0
  194. package/runtime/syntax/swift.yaml +103 -0
  195. package/runtime/syntax/systemd.yaml +16 -0
  196. package/runtime/syntax/tcl.yaml +18 -0
  197. package/runtime/syntax/terraform.yaml +87 -0
  198. package/runtime/syntax/tex.yaml +32 -0
  199. package/runtime/syntax/toml.yaml +56 -0
  200. package/runtime/syntax/twig.yaml +55 -0
  201. package/runtime/syntax/typescript.yaml +49 -0
  202. package/runtime/syntax/v.yaml +80 -0
  203. package/runtime/syntax/vala.yaml +26 -0
  204. package/runtime/syntax/verilog.yaml +60 -0
  205. package/runtime/syntax/vhdl.yaml +37 -0
  206. package/runtime/syntax/vi.yaml +31 -0
  207. package/runtime/syntax/vue.yaml +64 -0
  208. package/runtime/syntax/xml.yaml +37 -0
  209. package/runtime/syntax/xresources.yaml +14 -0
  210. package/runtime/syntax/yaml.yaml +34 -0
  211. package/runtime/syntax/yum.yaml +12 -0
  212. package/runtime/syntax/zig.yaml +52 -0
  213. package/runtime/syntax/zscript.yaml +72 -0
  214. package/runtime/syntax/zsh.yaml +52 -0
  215. package/src/buffer/buffer.js +126 -0
  216. package/src/buffer/loc.js +38 -0
  217. package/src/buffer/message.js +29 -0
  218. package/src/config/colorscheme.js +109 -0
  219. package/src/config/config.js +118 -0
  220. package/src/config/defaults.js +102 -0
  221. package/src/display/ansi-style.js +60 -0
  222. package/src/highlight/highlighter.js +237 -0
  223. package/src/highlight/parser.js +137 -0
  224. package/src/index.js +5942 -0
  225. package/src/lua/engine.js +38 -0
  226. package/src/platform/archive.js +50 -0
  227. package/src/platform/clipboard.js +160 -0
  228. package/src/platform/commands.js +140 -0
  229. package/src/plugins/js-bridge.js +902 -0
  230. package/src/plugins/manager.js +619 -0
  231. package/src/runtime/registry.js +89 -0
  232. package/src/screen/cell-buffer.js +81 -0
  233. package/src/screen/events.js +263 -0
  234. package/src/screen/screen.js +118 -0
  235. package/src/screen/vt100.js +391 -0
  236. package/src/shell/shell.js +70 -0
  237. package/todo.txt +359 -0
@@ -0,0 +1,108 @@
1
+ // example.js — demonstrates the micro JS plugin API
2
+ // No imports needed: `micro` is available as a global.
3
+
4
+ /*
5
+
6
+ # JS Plugin Documentation
7
+
8
+ Available hooks (register with micro.on(hookName, fn)):
9
+
10
+ Lifecycle (no args):
11
+ "preinit" — before plugins load
12
+ "init" — main plugin setup, register commands/actions here
13
+ "postinit" — after all plugins loaded
14
+
15
+ Buffer events:
16
+ "onBufferOpen" (buffer) — buffer opened (raw BufferModel, not pane adapter)
17
+ "onBufferClose" (buffer) — buffer closed (raw BufferModel)
18
+ "onSetActive" (bp) — pane became active (tab switch, close, etc.)
19
+ "onSave" (bp) — buffer saved
20
+
21
+ Input events:
22
+ "onRune" (bp, ch) — printable character inserted (ch is the string)
23
+
24
+ Cancellable hooks (return false to cancel the action):
25
+ "preBackspace" (bp) — before backspace; return false to block
26
+ "preInsertNewline" (bp) — before Enter/newline; return false to block
27
+
28
+ bp is a pane adapter with:
29
+ bp.Buf.Line(n) bp.Buf.LinesNum() bp.Buf.FileType()
30
+ bp.Buf.Insert(loc, text) bp.Buf.Replace(s, e, text)
31
+ bp.Cursor.X bp.Cursor.Y bp.Cursor.Loc bp.Cursor.HasSelection()
32
+ bp.Save() bp.Backspace() bp.CursorLeft/Right() bp.InsertNewline()
33
+
34
+ Flat buffer helpers (all 1-based line numbers, omit → cursor line):
35
+ micro.getLine(n?) micro.putLine(text, n?) micro.delLine(n?)
36
+ micro.getLines(from?, to?) micro.getLinesCount()
37
+ micro.getAllText() — entire buffer as one string (lines joined by "\n")
38
+ micro.putAllText(text) — replace entire buffer content; pushes undo
39
+ micro.getSelection() micro.putSelection(text)
40
+
41
+ Other micro APIs:
42
+ micro.CurPane() — returns pane adapter for active pane
43
+ micro.MakeCommand(name, fn) — register Ctrl+E command; fn(bp, args[])
44
+ micro.RegisterAction(name, fn) — register bindable action
45
+ micro.TermMessage(msg) — show msg in editor status row
46
+ micro.alert(msg) — suspend editor, print msg, wait for Enter
47
+ micro.Log(...args) — console.log passthrough
48
+ micro.GetOption(name) micro.SetOption(name, value)
49
+ micro.cmd.save() — call any editor command via proxy
50
+ micro.action.CursorUp() — run any registered action via proxy
51
+ micro.shell.CMD(...args) — run CMD interactively (same as Ctrl-B); async
52
+ e.g. await micro.shell.ls('-l')
53
+ await micro.shell.git('diff', '--stat')
54
+
55
+ */
56
+
57
+ micro.on("init", () => {
58
+ // Register a custom Ctrl+E command
59
+
60
+
61
+ micro.MakeCommand("nextchapter", async (bp, args) =>
62
+ {
63
+ let fp=bp?.Buf?.Path
64
+ let i1=fp.lastIndexOf('/')- -1
65
+ let i2=fp.lastIndexOf('.')
66
+ let nb=fp.slice(i1,i2)
67
+ let nfp=fp.slice(0,i1)+(nb- -1)+fp.slice(i2)
68
+
69
+ await micro.cmd.open('-f',nfp)
70
+
71
+ /*
72
+ await micro.cmd.replaceall('曰','日')
73
+ await micro.cmd.replaceall('修土','修士')
74
+ await micro.cmd.replaceall('<p>','\n')
75
+ await micro.cmd.replaceall('</p>','\n')
76
+ await micro.cmd.goto(48)
77
+
78
+
79
+ micro.cmd.tts()
80
+ */
81
+
82
+ });
83
+
84
+ micro.MakeCommand("prevchapter", async (bp, args) =>
85
+ {
86
+ let fp=bp?.Buf?.Path
87
+ let i1=fp.lastIndexOf('/')- -1
88
+ let i2=fp.lastIndexOf('.')
89
+ let nb=fp.slice(i1,i2)
90
+ let nfp=fp.slice(0,i1)+(nb-1)+fp.slice(i2)
91
+
92
+ await micro.cmd.open('-f',nfp)
93
+
94
+ /*
95
+ await micro.cmd.replaceall('曰','日')
96
+ await micro.cmd.replaceall('修土','修士')
97
+ await micro.cmd.replaceall('<p>','\n')
98
+ await micro.cmd.replaceall('</p>','\n')
99
+ await micro.cmd.goto(48)
100
+
101
+ micro.cmd.tts()
102
+ */
103
+
104
+ });
105
+
106
+ });
107
+
108
+
@@ -0,0 +1,46 @@
1
+ // diff.js — JS port of the Lua diff plugin (Go parity)
2
+ // When diffgutter is enabled, fetches git HEAD content and sets it as the
3
+ // diff base so the editor can show added/modified/removed gutter markers.
4
+ //
5
+ // Go behavior (diff.lua):
6
+ // 1. Skip scratch buffers or buffers with no path.
7
+ // 2. Check the file exists on disk; skip if not.
8
+ // 3. Run: git -C <dir> show HEAD:./<file>
9
+ // 4. On git failure (not tracked / no commits): set diffBase = current file
10
+ // content — this produces no gutter markers (base == current).
11
+ // 5. On success: set diffBase = git HEAD content.
12
+
13
+ import { dirname, basename } from "node:path";
14
+ import { existsSync } from "node:fs";
15
+
16
+ const _hasGit = await Bun.which("git") !== null;
17
+
18
+ micro.on("onBufferOpen", async (buffer) => {
19
+ if (!_hasGit) return;
20
+ if (!buffer.Settings?.diffgutter) return;
21
+ if (buffer.Type?.Scratch) return;
22
+ const absPath = buffer.AbsPath || buffer.Path;
23
+ if (!absPath) return;
24
+
25
+ // Go: os.Stat check — only proceed if the file exists on disk
26
+ try { if (!existsSync(absPath)) return; } catch { return; }
27
+
28
+ const dir = dirname(absPath);
29
+ const file = basename(absPath);
30
+ try {
31
+ const proc = Bun.spawn(["git", "-C", dir, "show", `HEAD:./${file}`], {
32
+ stdio: ["ignore", "pipe", "pipe"],
33
+ });
34
+ const exitCode = await proc.exited;
35
+ if (exitCode === 0) {
36
+ const text = await new Response(proc.stdout).text();
37
+ buffer.SetDiffBase(text);
38
+ } else {
39
+ // Go: on git failure set diffBase = current content (no markers shown)
40
+ buffer.SetDiffBase(buffer.Bytes ? buffer.Bytes() : "");
41
+ }
42
+ } catch (e) {
43
+ // Go: on error set diffBase = current content (no markers shown)
44
+ buffer.SetDiffBase(buffer.Bytes ? buffer.Bytes() : "");
45
+ }
46
+ });
@@ -0,0 +1,108 @@
1
+ // example.js — demonstrates the micro JS plugin API
2
+ // No imports needed: `micro` is available as a global.
3
+
4
+ /*
5
+
6
+ # JS Plugin Documentation
7
+
8
+ Available hooks (register with micro.on(hookName, fn)):
9
+
10
+ Lifecycle (no args):
11
+ "preinit" — before plugins load
12
+ "init" — main plugin setup, register commands/actions here
13
+ "postinit" — after all plugins loaded
14
+
15
+ Buffer events:
16
+ "onBufferOpen" (buffer) — buffer opened (raw BufferModel, not pane adapter)
17
+ "onBufferClose" (buffer) — buffer closed (raw BufferModel)
18
+ "onSetActive" (bp) — pane became active (tab switch, close, etc.)
19
+ "onSave" (bp) — buffer saved
20
+
21
+ Input events:
22
+ "onRune" (bp, ch) — printable character inserted (ch is the string)
23
+
24
+ Cancellable hooks (return false to cancel the action):
25
+ "preBackspace" (bp) — before backspace; return false to block
26
+ "preInsertNewline" (bp) — before Enter/newline; return false to block
27
+
28
+ bp is a pane adapter with:
29
+ bp.Buf.Line(n) bp.Buf.LinesNum() bp.Buf.FileType()
30
+ bp.Buf.Insert(loc, text) bp.Buf.Replace(s, e, text)
31
+ bp.Cursor.X bp.Cursor.Y bp.Cursor.Loc bp.Cursor.HasSelection()
32
+ bp.Save() bp.Backspace() bp.CursorLeft/Right() bp.InsertNewline()
33
+
34
+ Flat buffer helpers (all 1-based line numbers, omit → cursor line):
35
+ micro.getLine(n?) micro.putLine(text, n?) micro.delLine(n?)
36
+ micro.getLines(from?, to?) micro.getLinesCount()
37
+ micro.getAllText() — entire buffer as one string (lines joined by "\n")
38
+ micro.putAllText(text) — replace entire buffer content; pushes undo
39
+ micro.getSelection() micro.putSelection(text)
40
+
41
+ Other micro APIs:
42
+ micro.CurPane() — returns pane adapter for active pane
43
+ micro.MakeCommand(name, fn) — register Ctrl+E command; fn(bp, args[])
44
+ micro.RegisterAction(name, fn) — register bindable action
45
+ micro.TermMessage(msg) — show msg in editor status row
46
+ micro.alert(msg) — suspend editor, print msg, wait for Enter
47
+ micro.Log(...args) — console.log passthrough
48
+ micro.GetOption(name) micro.SetOption(name, value)
49
+ micro.cmd.save() — call any editor command via proxy
50
+ micro.action.CursorUp() — run any registered action via proxy
51
+ micro.shell.CMD(...args) — run CMD interactively (same as Ctrl-B); async
52
+ e.g. await micro.shell.ls('-l')
53
+ await micro.shell.git('diff', '--stat')
54
+
55
+ */
56
+
57
+ micro.on("init", () => {
58
+ // Register a custom Ctrl+E command
59
+ micro.MakeCommand("showpath", async (bp, args) =>
60
+ {
61
+ //micro.TermMessage("Hello from JS plugin! Args: " + args.join(", "));
62
+
63
+ //await micro.alert(micro.getLine())
64
+ await micro.alert(bp?.Buf?.Path || "(no path)")
65
+
66
+ });
67
+
68
+
69
+ micro.MakeCommand("js", async (bp, args) =>
70
+ {
71
+ let scriptText=args.join("\n");
72
+
73
+ await micro.alert(
74
+ await eval(scriptText)
75
+ )
76
+
77
+ });
78
+
79
+
80
+ // greet: shows a message via micro.alert (leaves editor, shows text, Enter returns)
81
+ micro.MakeCommand("greet", async (bp, args) =>
82
+ {
83
+ const name = args.length ?
84
+ args.join(" ") : "world";
85
+
86
+ let s=Bun.markdown.ansi(
87
+ '# Hello\n- '+name
88
+ );
89
+
90
+ await micro.alert(s);
91
+ });
92
+
93
+ // Register a custom action (can be bound to a key in keybindings.json)
94
+ micro.RegisterAction("ExampleDuplicateAndComment", async () =>
95
+ {
96
+ await micro.action.DuplicateLine();
97
+ await micro.action.ToggleComment();
98
+ });
99
+ });
100
+
101
+ micro.on("onSave", (bp) =>
102
+ {
103
+ // bp is the BufPane adapter
104
+ // (same as Lua's bp arg)
105
+
106
+ const path = bp?.Buf?.Path || "(no path)";
107
+ //micro.Log("[example] saved:", path);
108
+ });
@@ -0,0 +1,281 @@
1
+ // linter.js — JS port of linter.lua
2
+ // Runs linters on save, adds gutter messages via bp.Buf.AddMessage.
3
+ // micro global is available as globalThis.micro.
4
+
5
+ import { basename, dirname } from "node:path";
6
+
7
+ const GOOS = process.platform === "win32" ? "windows" : process.platform;
8
+ const devnull = GOOS === "windows" ? "NUL" : "/dev/null";
9
+
10
+ // ── Linter registry ───────────────────────────────────────────────────────────
11
+
12
+ const linters = new Map();
13
+
14
+ function makeLinter(name, filetype, cmd, args, errorformat, {
15
+ os: osList = [], whitelist = false, domatch = false, loffset = 0, coffset = 0,
16
+ } = {}) {
17
+ linters.set(name, { filetype, cmd, args, errorformat, osList, whitelist, domatch, loffset, coffset });
18
+ }
19
+
20
+ function removeLinter(name) { linters.delete(name); }
21
+
22
+ // ── Registrations (mirrors linter.lua preinit) ────────────────────────────────
23
+
24
+ makeLinter("gcc", "c", "gcc", ["-fsyntax-only", "-Wall", "-Wextra", "%f"], "%f:%l:%c:.+: %m");
25
+ makeLinter("g++", "c++", "g++", ["-fsyntax-only", "-Wall", "-Wextra", "%f"], "%f:%l:%c:.+: %m");
26
+ makeLinter("dmd", "d", "dmd", ["-color=off", "-o-", "-w", "-wi", "-c", "%f"], "%f%(%l%):.+: %m");
27
+ makeLinter("ldc2", "d", "ldc2", ["--o-", "--vcolumns", "-w", "-c", "%f"], "%f%(%l,%c%):[^:]+: %m");
28
+ makeLinter("gdc", "d", "gdc", ["-fsyntax-only", "-Wall", "-Wextra", "%f"], "%f:%l:%c:.+: %m");
29
+ makeLinter("eslint", "javascript", "eslint", ["-f", "json", "--no-ignore", "%f"], null); // JSON parsing
30
+ makeLinter("gobuild", "go", "go", ["build", "-o", devnull, "%d"], "%f:%l:%c:? %m");
31
+ makeLinter("govet", "go", "go", ["vet"], "%f:%l:%c: %m");
32
+ makeLinter("clippy", "rust", "cargo", ["clippy", "--message-format", "short"], "%f:%l:%c: %m");
33
+ makeLinter("hlint", "haskell", "hlint", ["%f"], "%f:%(?%l[,:]%c%)?.-: %m");
34
+ makeLinter("javac", "java", "javac", ["-d", "%d", "%f"], "%f:%l: error: %m");
35
+ makeLinter("jshint", "javascript", "jshint", ["%f"], "%f: line %l,.+, %m");
36
+ makeLinter("literate", "literate", "lit", ["-c", "%f"], "%f:%l:%m", { domatch: true });
37
+ makeLinter("luacheck", "lua", "luacheck", ["--no-color", "%f"], "%f:%l:%c: %m");
38
+ makeLinter("nim", "nim", "nim", ["check", "--listFullPaths", "--stdout", "--hints:off", "%f"], "%f.%l, %c. %m");
39
+ makeLinter("clang", "objective-c", "xcrun", ["clang", "-fsyntax-only", "-Wall", "-Wextra", "%f"], "%f:%l:%c:.+: %m");
40
+ makeLinter("pyflakes", "python", "pyflakes", ["%f"], "%f:%l:.-:? %m");
41
+ makeLinter("mypy", "python", "mypy", ["%f"], "%f:%l: %m");
42
+ makeLinter("pylint", "python", "pylint", ["--output-format=parseable", "--reports=no", "%f"], "%f:%l: %m");
43
+ makeLinter("ruff", "python", "ruff", ["check", "--output-format=concise", "%f"], "%f:%l:%c: %m");
44
+ makeLinter("flake8", "python", "flake8", ["%f"], "%f:%l:%c: %m");
45
+ makeLinter("shfmt", "shell", "shfmt", ["%f"], "%f:%l:%c: %m");
46
+ makeLinter("shellcheck", "shell", "shellcheck", ["-f", "gcc", "%f"], "%f:%l:%c:.+: %m");
47
+ makeLinter("swiftc", "swift", "xcrun", ["swiftc", "%f"], "%f:%l:%c:.+: %m", { os: ["darwin"], whitelist: true });
48
+ makeLinter("swiftc-linux","swift", "swiftc", ["%f"], "%f:%l:%c:.+: %m", { os: ["linux"], whitelist: true });
49
+ makeLinter("yaml", "yaml", "yamllint", ["--format", "parsable", "%f"], "%f:%l:%c:.+ %m");
50
+ makeLinter("nix-linter", "nix", "nix-linter", ["%f"], "%m at %f:%l:%c", { os: ["linux"], whitelist: true });
51
+
52
+ // ── Errorformat → JS regex ────────────────────────────────────────────────────
53
+
54
+ function parseErrorformat(ef) {
55
+ const captures = [];
56
+ let out = "";
57
+ let i = 0;
58
+
59
+ while (i < ef.length) {
60
+ if (ef[i] === "%") {
61
+ const next = ef[i + 1] ?? "";
62
+ i += 2;
63
+ switch (next) {
64
+ case "f": captures.push("f"); out += "(.+?)"; break;
65
+ case "l": captures.push("l"); out += "(\\d+)"; break;
66
+ case "c": captures.push("c"); out += "(\\d+)"; break;
67
+ case "m": captures.push("m"); out += "(.+)"; break;
68
+ case "%": out += "%"; break;
69
+ case "d": out += "\\d"; break;
70
+ case "D": out += "\\D"; break;
71
+ case "s": out += "\\s"; break;
72
+ case "S": out += "\\S"; break;
73
+ case "w": out += "\\w"; break;
74
+ case "W": out += "\\W"; break;
75
+ case "a": out += "[a-zA-Z]"; break;
76
+ default:
77
+ // Lua punctuation escape → literal, JS-escaped
78
+ out += next.replace(/[.+*?^${}()|[\]\\]/g, "\\$&");
79
+ break;
80
+ }
81
+ continue;
82
+ }
83
+
84
+ if (ef[i] === "[") {
85
+ let cls = "[";
86
+ i++;
87
+ while (i < ef.length && ef[i] !== "]") {
88
+ if (ef[i] === "%") {
89
+ const nc = ef[i + 1] ?? "";
90
+ i += 2;
91
+ if (nc === "s") cls += "\\s";
92
+ else if (nc === "S") cls += "\\S";
93
+ else if (nc === "d") cls += "\\d";
94
+ else if (nc === "w") cls += "\\w";
95
+ else if (nc === "%") cls += "%";
96
+ else cls += nc;
97
+ } else {
98
+ cls += ef[i++];
99
+ }
100
+ }
101
+ cls += "]";
102
+ if (ef[i] === "]") i++;
103
+ out += cls;
104
+ continue;
105
+ }
106
+
107
+ // Lua `.-` (lazy any) → JS `.*?`
108
+ if (ef[i] === "." && ef[i + 1] === "-") {
109
+ out += ".*?";
110
+ i += 2;
111
+ continue;
112
+ }
113
+
114
+ // `|` is literal in Lua patterns but special in JS regex
115
+ if (ef[i] === "|" || ef[i] === "{" || ef[i] === "}") {
116
+ out += "\\" + ef[i++];
117
+ continue;
118
+ }
119
+
120
+ out += ef[i++];
121
+ }
122
+
123
+ return { regex: new RegExp(out), captures };
124
+ }
125
+
126
+ const _parsedCache = new Map();
127
+ function getParsed(ef) {
128
+ if (!_parsedCache.has(ef)) _parsedCache.set(ef, parseErrorformat(ef));
129
+ return _parsedCache.get(ef);
130
+ }
131
+
132
+ // ── eslint JSON output parsing ────────────────────────────────────────────────
133
+
134
+ function parseEslintJson(output, bufPath) {
135
+ let results;
136
+ try { results = JSON.parse(output); } catch { return null; }
137
+ if (!Array.isArray(results)) return null;
138
+
139
+ const msgs = [];
140
+ const bufBase = basename(bufPath);
141
+ for (const file of results) {
142
+ if (!file?.messages || basename(file.filePath ?? "") !== bufBase) continue;
143
+ for (const m of file.messages) {
144
+ msgs.push({
145
+ line: m.line ?? 1,
146
+ col: m.column ?? 1,
147
+ msg: m.message ?? "",
148
+ severity: (m.severity ?? 2) >= 2 ? micro.buffer.MTError : micro.buffer.MTWarning,
149
+ });
150
+ }
151
+ }
152
+ return msgs;
153
+ }
154
+
155
+ // ── OS filter ─────────────────────────────────────────────────────────────────
156
+
157
+ function checkFtMatch(ft, v) {
158
+ let ftmatch = v.domatch ? new RegExp(v.filetype).test(ft) : ft === v.filetype;
159
+ if (!ftmatch) return false;
160
+ const hasOS = v.osList.includes(GOOS);
161
+ if (!hasOS && v.whitelist) return false;
162
+ if (hasOS && !v.whitelist) return false;
163
+ return true;
164
+ }
165
+
166
+ // ── Spawn + parse ─────────────────────────────────────────────────────────────
167
+
168
+ async function spawnAndCollect(argv) {
169
+ let proc;
170
+ try {
171
+ proc = Bun.spawn(argv, { stdout: "pipe", stderr: "pipe", stdin: "ignore" });
172
+ } catch (err) {
173
+ micro.pushLintLog(`[linter:${argv[0]}] spawn failed: ${err.message}`);
174
+ return null;
175
+ }
176
+ const dec = new TextDecoder();
177
+ const readAll = async (stream) => {
178
+ const chunks = [];
179
+ if (!stream) return "";
180
+ const reader = stream.getReader();
181
+ while (true) {
182
+ const { done, value } = await reader.read();
183
+ if (done) break;
184
+ chunks.push(dec.decode(value, { stream: true }));
185
+ }
186
+ return chunks.join("");
187
+ };
188
+ try {
189
+ const [out, err] = await Promise.all([readAll(proc.stdout), readAll(proc.stderr)]);
190
+ await proc.exited;
191
+ return out + err;
192
+ } catch (err) {
193
+ micro.pushLintLog(`[linter:${argv[0]}] read failed: ${err.message}`);
194
+ return null;
195
+ }
196
+ }
197
+
198
+ async function lint(bufAdapter, linterName, v) {
199
+ const file = bufAdapter.Path ?? bufAdapter.path ?? "";
200
+ const dir = dirname(file) || ".";
201
+
202
+ const argv = [v.cmd, ...v.args.map(a => a.replace(/%f/g, file).replace(/%d/g, dir))];
203
+ const output = await spawnAndCollect(argv);
204
+ if (output == null) return;
205
+
206
+ bufAdapter.ClearMessages(linterName);
207
+
208
+ // eslint: JSON path
209
+ if (v.errorformat === null) {
210
+ const msgs = parseEslintJson(output, file);
211
+ if (!msgs) {
212
+ if (output.trim()) micro.pushLintLog(`[linter:${linterName}]\n${output.trim()}`);
213
+ return;
214
+ }
215
+ for (const { line, col, msg, severity } of msgs) {
216
+ const start = micro.buffer.Loc(col - 1 + v.coffset, line - 1 + v.loffset);
217
+ const end = micro.buffer.Loc(col + v.coffset, line - 1 + v.loffset);
218
+ bufAdapter.AddMessage(micro.buffer.newMessage(linterName, msg, start, end, severity));
219
+ }
220
+ micro.render();
221
+ return;
222
+ }
223
+
224
+ // Generic errorformat path
225
+ const { regex, captures } = getParsed(v.errorformat);
226
+ const hasCol = captures.includes("c");
227
+ const bufBase = basename(file);
228
+
229
+ for (let rawLine of output.split("\n")) {
230
+ rawLine = rawLine.replace(/^\s+|\s+$/g, "");
231
+ if (!rawLine) continue;
232
+ const m = regex.exec(rawLine);
233
+ if (!m) continue;
234
+
235
+ const capMap = {};
236
+ captures.forEach((k, idx) => { capMap[k] = m[idx + 1]; });
237
+
238
+ if (!capMap.f || basename(capMap.f) !== bufBase) continue;
239
+
240
+ const lineNum = Number(capMap.l ?? 1);
241
+ const colNum = Number(capMap.c ?? 1);
242
+ const msg = capMap.m ?? "";
243
+
244
+ let bmsg;
245
+ if (hasCol && capMap.c != null) {
246
+ const start = micro.buffer.Loc(colNum - 1 + v.coffset, lineNum - 1 + v.loffset);
247
+ const end = micro.buffer.Loc(colNum + v.coffset, lineNum - 1 + v.loffset);
248
+ bmsg = micro.buffer.newMessage(linterName, msg, start, end, micro.buffer.MTError);
249
+ } else {
250
+ bmsg = micro.buffer.newMessageAtLine(linterName, msg, lineNum + v.loffset, micro.buffer.MTError);
251
+ }
252
+ bufAdapter.AddMessage(bmsg);
253
+ }
254
+ micro.render();
255
+ }
256
+
257
+ async function runLinter(bp) {
258
+ const ft = bp.Buf.FileType();
259
+ const buf = bp.Buf;
260
+
261
+ for (const [name, v] of linters) {
262
+ if (!checkFtMatch(ft, v)) continue;
263
+ lint(buf, name, v).catch(e => micro.pushLintLog(`[linter:${name}] ${e.message}`));
264
+ }
265
+ }
266
+
267
+ // ── Hook registration ─────────────────────────────────────────────────────────
268
+
269
+ micro.on("init", () => {
270
+ micro.MakeCommand("lint", async (bp) => {
271
+ await bp.Save();
272
+ await runLinter(bp);
273
+ });
274
+ });
275
+
276
+ micro.on("onSave", (bp) => {
277
+ runLinter(bp).catch(e => micro.pushLintLog(`[linter:onSave] ${e.message}`));
278
+ });
279
+
280
+ // Expose API for user init.js to override linter definitions
281
+ globalThis.linter = { makeLinter, removeLinter, linters };
@@ -0,0 +1,75 @@
1
+ VERSION = "1.0.0"
2
+
3
+ local uutil = import("micro/util")
4
+ local utf8 = import("utf8")
5
+ local autoclosePairs = {"\"\"", "''", "``", "()", "{}", "[]"}
6
+ local autoNewlinePairs = {"()", "{}", "[]"}
7
+
8
+ function charAt(str, i)
9
+ -- lua indexing is one off from go
10
+ return uutil.RuneAt(str, i-1)
11
+ end
12
+
13
+ function onRune(bp, r)
14
+ for i = 1, #autoclosePairs do
15
+ if r == charAt(autoclosePairs[i], 2) then
16
+ local curLine = bp.Buf:Line(bp.Cursor.Y)
17
+
18
+ if charAt(curLine, bp.Cursor.X+1) == charAt(autoclosePairs[i], 2) then
19
+ bp:Backspace()
20
+ bp:CursorRight()
21
+ break
22
+ end
23
+
24
+ if bp.Cursor.X > 1 and (uutil.IsWordChar(charAt(curLine, bp.Cursor.X-1)) or charAt(curLine, bp.Cursor.X-1) == charAt(autoclosePairs[i], 1)) then
25
+ break
26
+ end
27
+ end
28
+ if r == charAt(autoclosePairs[i], 1) then
29
+ local curLine = bp.Buf:Line(bp.Cursor.Y)
30
+
31
+ if bp.Cursor.X == uutil.CharacterCountInString(curLine) or not uutil.IsWordChar(charAt(curLine, bp.Cursor.X+1)) then
32
+ -- the '-' here is to derefence the pointer to bp.Cursor.Loc which is automatically made
33
+ -- when converting go structs to lua
34
+ -- It needs to be dereferenced because the function expects a non pointer struct
35
+ bp.Buf:Insert(-bp.Cursor.Loc, charAt(autoclosePairs[i], 2))
36
+ bp:CursorLeft()
37
+ break
38
+ end
39
+ end
40
+ end
41
+ return true
42
+ end
43
+
44
+ function preInsertNewline(bp)
45
+ local curLine = bp.Buf:Line(bp.Cursor.Y)
46
+ local curRune = charAt(curLine, bp.Cursor.X)
47
+ local nextRune = charAt(curLine, bp.Cursor.X+1)
48
+ local ws = uutil.GetLeadingWhitespace(curLine)
49
+
50
+ for i = 1, #autoNewlinePairs do
51
+ if curRune == charAt(autoNewlinePairs[i], 1) then
52
+ if nextRune == charAt(autoNewlinePairs[i], 2) then
53
+ bp.Buf:Insert(-bp.Cursor.Loc, "\n" .. ws)
54
+ bp:StartOfLine()
55
+ bp:CursorLeft()
56
+ bp:InsertNewline()
57
+ bp:InsertTab()
58
+ return false
59
+ end
60
+ end
61
+ end
62
+
63
+ return true
64
+ end
65
+
66
+ function preBackspace(bp)
67
+ for i = 1, #autoclosePairs do
68
+ local curLine = bp.Buf:Line(bp.Cursor.Y)
69
+ if charAt(curLine, bp.Cursor.X+1) == charAt(autoclosePairs[i], 2) and charAt(curLine, bp.Cursor.X) == charAt(autoclosePairs[i], 1) then
70
+ bp:Delete()
71
+ end
72
+ end
73
+
74
+ return true
75
+ end
@@ -0,0 +1,17 @@
1
+ VERSION = "1.0.0"
2
+
3
+ function onBufferOpen(b)
4
+ local ft = b:FileType()
5
+
6
+ if ft == "go" or
7
+ ft == "makefile" then
8
+ b:SetOption("tabstospaces", "off")
9
+ elseif ft == "fish" or
10
+ ft == "python" or
11
+ ft == "python2" or
12
+ ft == "python3" or
13
+ ft == "yaml" or
14
+ ft == "nim" then
15
+ b:SetOption("tabstospaces", "on")
16
+ end
17
+ end
@@ -0,0 +1,5 @@
1
+ # Literate Micro
2
+
3
+ Support for reading `.lit` files from [zyedidia/Literate](https://github.com/zyedidia/Literate).
4
+
5
+ This plugin will automatically detect the filetype and highlight the correct language inside the code blocks.