bunmicro 0.9.19 → 0.9.20

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.20] - 2026-06-07
4
+ - Added cursor shape option
5
+ - Fixed selection hide cursor
6
+
3
7
  ## [0.9.19] - 2026-06-06
4
8
  - Fixed Windows clipboard
5
9
  - Fixed cli encoding help readme
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bunmicro",
3
- "version": "0.9.19",
3
+ "version": "0.9.20",
4
4
  "description": "Bun JavaScript rewrite of the micro editor originally in Golang",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -94,6 +94,13 @@ Here are the available options:
94
94
 
95
95
  default value: `true`
96
96
 
97
+ * `cursorshape`: sets the editor cursor shape using the terminal's DECSCUSR
98
+ support. This setting is `global only`. Supported values are `default`,
99
+ `block`, `underline`, `bar`, and their `blinking-` variants. The plain
100
+ shape names use a steady cursor.
101
+
102
+ default value: `block`
103
+
97
104
  * `detectlimit`: if this is not set to 0, it will limit the amount of first
98
105
  lines in a file that are matched to determine the filetype.
99
106
  A higher limit means better accuracy of guessing the filetype, but also
@@ -566,6 +573,7 @@ so that you can see what the formatting should look like.
566
573
  "colorscheme": "default",
567
574
  "comment": true,
568
575
  "cursorline": true,
576
+ "cursorshape": "block",
569
577
  "detectlimit": 100,
570
578
  "diff": true,
571
579
  "diffgutter": false,
@@ -57,6 +57,7 @@ export const DEFAULT_GLOBAL_ONLY_SETTINGS = {
57
57
  autosave: 0,
58
58
  clipboard: "external",
59
59
  colorscheme: "default",
60
+ cursorshape: "block",
60
61
  savehistory: true,
61
62
  divchars: "|-",
62
63
  divreverse: true,
@@ -81,6 +82,12 @@ export const DEFAULT_GLOBAL_ONLY_SETTINGS = {
81
82
 
82
83
  export const OPTION_CHOICES = {
83
84
  clipboard: ["internal", "external", "terminal"],
85
+ cursorshape: [
86
+ "default",
87
+ "block", "blinking-block",
88
+ "underline", "blinking-underline",
89
+ "bar", "blinking-bar",
90
+ ],
84
91
  fileformat: ["unix", "dos"],
85
92
  helpsplit: ["hsplit", "vsplit"],
86
93
  matchbracestyle: ["underline", "highlight"],
package/src/index.js CHANGED
@@ -81,6 +81,7 @@ const DEFAULT_SETTINGS = {
81
81
  tabsize: 4,
82
82
  tabstospaces: false,
83
83
  autosave: 0,
84
+ cursorshape: "block",
84
85
  cursorline: true,
85
86
  diffgutter: false,
86
87
  eofnewline: true,
@@ -1249,6 +1250,9 @@ class BufferModel {
1249
1250
  SetOption(option, value) {
1250
1251
  const oldValue = this.Settings[option];
1251
1252
  const parsed = parseOptionValue(value);
1253
+ if (option === "cursorshape" && !OPTION_CHOICES.cursorshape.includes(String(parsed))) {
1254
+ throw new Error(`Invalid value for cursorshape: ${parsed}`);
1255
+ }
1252
1256
  if (option === "fileformat" && !OPTION_CHOICES.fileformat.includes(String(parsed))) {
1253
1257
  throw new Error(`Invalid value for fileformat: ${parsed}`);
1254
1258
  }
@@ -1263,6 +1267,9 @@ class BufferModel {
1263
1267
 
1264
1268
  DoSetOptionNative(option, value) {
1265
1269
  const oldValue = this.Settings[option];
1270
+ if (option === "cursorshape" && !OPTION_CHOICES.cursorshape.includes(String(value))) {
1271
+ throw new Error(`Invalid value for cursorshape: ${value}`);
1272
+ }
1266
1273
  if (option === "fileformat" && !OPTION_CHOICES.fileformat.includes(String(value))) {
1267
1274
  throw new Error(`Invalid value for fileformat: ${value}`);
1268
1275
  }
@@ -1966,8 +1973,19 @@ class App {
1966
1973
  cursorCol = p.x + gutterW + displayWidth(line.slice(buf.scroll.x, cursorX));
1967
1974
  }
1968
1975
 
1969
- const cursorVisible = cursorRow >= p.y && cursorRow < p.y + p.h && cursorCol >= p.x && cursorCol < p.x + p.w;
1970
- this.screen.setCursor(clamp(cursorCol, 0, this.cols - 1), clamp(cursorRow, 0, this.rows - 1), cursorVisible, "steady-block");
1976
+ // Go micro hides the terminal cursor while a non-empty selection is
1977
+ // active. Otherwise its block cursor makes the exclusive selection end
1978
+ // look selected even though copy/cut correctly omit that character.
1979
+ const hasSelection = p.selection && !sameLoc(p.selection.start, p.selection.end);
1980
+ const cursorVisible = !hasSelection &&
1981
+ cursorRow >= p.y && cursorRow < p.y + p.h &&
1982
+ cursorCol >= p.x && cursorCol < p.x + p.w;
1983
+ this.screen.setCursor(
1984
+ clamp(cursorCol, 0, this.cols - 1),
1985
+ clamp(cursorRow, 0, this.rows - 1),
1986
+ cursorVisible,
1987
+ DEFAULT_SETTINGS.cursorshape,
1988
+ );
1971
1989
  } else if (!this.prompt && activePaneObj?.type !== "term") {
1972
1990
  this.screen.setCursor(0, 0, false);
1973
1991
  }
@@ -3,6 +3,20 @@ import { styleToAnsi } from "../display/ansi-style.js";
3
3
  import { CellBuffer } from "./cell-buffer.js";
4
4
  import { DISABLE_MOUSE, DISABLE_PASTE, ENABLE_MOUSE, ENABLE_PASTE, ResizeEvent } from "./events.js";
5
5
 
6
+ const CURSOR_SHAPE_SEQUENCE = {
7
+ default: "\x1b[0 q",
8
+ "blinking-block": "\x1b[1 q",
9
+ block: "\x1b[2 q",
10
+ "blinking-underline": "\x1b[3 q",
11
+ underline: "\x1b[4 q",
12
+ "blinking-bar": "\x1b[5 q",
13
+ bar: "\x1b[6 q",
14
+ };
15
+
16
+ export function cursorShapeSequence(shape) {
17
+ return CURSOR_SHAPE_SEQUENCE[shape] ?? CURSOR_SHAPE_SEQUENCE.block;
18
+ }
19
+
6
20
  export class Screen {
7
21
  constructor({ mouse = true } = {}) {
8
22
  this.mouse = mouse;
@@ -23,7 +37,7 @@ export class Screen {
23
37
  fini() {
24
38
  if (this.mouse) this.write(DISABLE_MOUSE);
25
39
  this.write(DISABLE_PASTE);
26
- this.write("\x1b[?25h\x1b[?1049l\x1b[0m");
40
+ this.write("\x1b[0 q\x1b[?25h\x1b[?1049l\x1b[0m");
27
41
  }
28
42
 
29
43
  SetContent(x, y, ch, combining = [], style = null) {
@@ -81,9 +95,7 @@ export class Screen {
81
95
  }
82
96
  out += "\x1b[0m";
83
97
  if (this.cursor && this.cursorVisible) {
84
- // cursor shape: 1/2=block, 3/4=underline, 5/6=bar; odd=blink even=steady
85
- const shape = this.cursor.shape === "bar" ? "\x1b[5 q" : this.cursor.shape === "steady-block" ? "\x1b[2 q" : "\x1b[1 q";
86
- out += shape + this.move(this.cursor.y + 1, this.cursor.x + 1) + "\x1b[?25h";
98
+ out += cursorShapeSequence(this.cursor.shape) + this.move(this.cursor.y + 1, this.cursor.x + 1) + "\x1b[?25h";
87
99
  } else out += "\x1b[?25l";
88
100
  this.write(out);
89
101
  this.previous = this.cells.clone();
package/todo.txt CHANGED
@@ -15,6 +15,7 @@ Current handoff notes
15
15
  - Always emits ANSI codes regardless of TTY state.
16
16
  - -profile removed from usage (flag parsed but never implemented in Go either; -debug kept for future log.txt work).
17
17
  [x] Recent editor UX parity implemented:
18
+ - Global cursorshape option supports common DECSCUSR cursor shapes: default, steady/blinking block, underline, and bar, with command completion.
18
19
  - Tab autocomplete candidate row cycles highlight correctly and only highlights the selected candidate text.
19
20
  - Tab autocomplete single-match case fixed: was silently no-op due to acHas=false; now inserts suffix directly.
20
21
  - Mouse click on autocomplete candidates no longer moves the editor cursor to the click location.