feat(VGA): export cursor method from asm
+ 149
- 79
@@ -2,6 +2,82 @@ bits 32
 
 extern kmain
 
+global set_cursor_pos
+global hide_cursor
+global show_cursor
+
+; Inputs: rdi = row, rsi = col
+set_cursor_pos:
+    push    ebp
+    mov     ebp, esp
+
+    mov     eax, dword [ebp + 8]    ; eax = row
+    mov     ebx, 80
+    imul    eax, ebx                ; eax = row * 80
+    add     eax, dword [ebp + 12]   ; eax += col
+    mov     bx, ax                  ; bx = position (16-bit)
+
+    ; outb(0x3D4, 0x0E);
+    mov     dx, 0x3D4
+    mov     al, 0x0E
+    out     dx, al
+
+    ; outb(0x3D5, (position >> 8) & 0xFF);
+    mov     dx, 0x3D5
+    mov     al, bh
+    out     dx, al
+
+    ; outb(0x3D4, 0x0F);
+    mov     dx, 0x3D4
+    mov     al, 0x0F
+    out     dx, al
+
+    ; outb(0x3D5, position & 0xFF);
+    mov     dx, 0x3D5
+    mov     al, bl
+    out     dx, al
+
+    mov     esp, ebp
+    pop     ebp
+    ret
+
+; void hide_cursor(void)
+hide_cursor:
+    ; Read: write index 0x0A, then write data with bit 5 set
+    ; For simplicity we don't read current value; we set start = 0x20 (disabled)
+    mov     dx, 0x3D4
+    mov     al, 0x0A
+    out     dx, al
+
+    mov     dx, 0x3D5
+    mov     al, 0x20    ; set bit 5 to disable cursor
+    out     dx, al
+
+    ret
+
+; void show_cursor(void)
+show_cursor:
+    ; Restore a typical cursor shape: start = 0 (scanline start)
+    mov     dx, 0x3D4
+    mov     al, 0x0A
+    out     dx, al
+
+    mov     dx, 0x3D5
+    mov     al, 0x00    ; cursor start = 0
+    out     dx, al
+
+    ; set cursor end (e.g., 15)
+    mov     dx, 0x3D4
+    mov     al, 0x0B
+    out     dx, al
+
+    mov     dx, 0x3D5
+    mov     al, 0x0F    ; cursor end = 15 (typical)
+    out     dx, al
+
+    ret
+
+
 section .entry
 
 ; void start()

@@ -27,19 +27,12 @@ fun kmain
     VGA::Colors::BLACK_ON_CYAN,
   )
   VGA.puts("\n")
-  VGA.puts("Hello world!\nWorks maybe?\n", line: 1)
-  VGA.puts("Can print on multiple lines\n", line: 2)
+  VGA.puts("Hello world!\n\nWorks maybe?\n", line: 1)
+  VGA.puts("Can print on multiple lines\n", line: 2, color: VGA::Colors::BLACK_ON_LIME)
   VGA.puts("But because we don't have a Heap, we need to set lines number in puts call for now...\n", line: 3)
-  # VGA.puts(%(
-  #   Works well
-  #   multiline buffer?
-  # ),
-  #   VGA::Colors::BLACK_ON_LIME,
-  # )
-  # VGA.puts("\n\n\n")
-  # VGA.puts "hello world\n"
   
-  #VGA.dump_cursor_and_cells
+  VGA.set_cursor(5, 4)
+  VGA.hide_cursor
 
   while true
     asm (%(hlt))

@@ -1,3 +1,13 @@
+lib KernelShim
+  # Definition in kernel/entry.asm
+  fun hide_cursor()
+  fun show_cursor()
+  fun set_cursor_pos(
+    row : UInt32,
+    col : UInt32
+  )
+end
+
 struct VGACursor
   col : Int32 = 0
   row : Int32 = 0

...
@@ -66,83 +76,74 @@ module VGA
     VGA_CURSOR.col = 0
     VGA_CURSOR.row = 0
   end
+  
+  # Hide cursor
+  def self.hide_cursor
+    KernelShim.hide_cursor
+  end
+  
+  # Show cursor
+  def self.show_cursor
+    KernelShim.show_cursor
+  end
 
+  # Set typing cursor position
+  def self.set_cursor(
+    col : Int32,
+    row : Int32
+  ) : Nil
+    KernelShim
+      .set_cursor_pos(row.to_u32, col.to_u32)
+  end
+  
   # Write a single character to the current cursor position
   def self.putchar(
-    ch : UInt8,
-    i : Int32? = 0,
-    line : Int32? = 0,
-    color : UInt8? = Colors::DEFAULT
+      ch : UInt8,
+      i : Int32? = 0,
+      line : Int32? = 0,
+      color : UInt8? = Colors::DEFAULT
   ) : Nil
-    VGA_CURSOR.col = i
-    VGA_CURSOR.row = line
+      VGA_CURSOR.col = i
+      VGA_CURSOR.row = line
   
-    # Simplified cursor handling (replace with actual cursor logic later)
-    if ch == ("\n".to_unsafe).value # 0x0A_u8 # \n
-      VGA_CURSOR.col = 0
-      VGA_CURSOR.row += 1
-      if VGA_CURSOR.row >= VGA_HEIGHT
-        VGA_CURSOR.row = VGA_HEIGHT - 1
+      if ch == 0x0A_u8 # \n (not working...)
+       # VGA_CURSOR.col = 0
+        VGA_CURSOR.row += 1
+        if VGA_CURSOR.row >= VGA_HEIGHT
+          VGA_CURSOR.row = VGA_HEIGHT - 1
+        end
+        ch = " ".to_unsafe.value
       end
-      return
-    end
-
-    offset = (VGA_CURSOR.row * VGA_WIDTH + VGA_CURSOR.col) * 2
-
-    (VGA_BUFFER + offset).value = ch
-    (VGA_BUFFER + offset + 1).value = color
-    
-    VGA_CURSOR.col += 1
-    
-    if VGA_CURSOR.col >= VGA_WIDTH
-      VGA_CURSOR.col = 0
-      VGA_CURSOR.row += 1
-      
-      if VGA_CURSOR.row >= VGA_HEIGHT
-        VGA_CURSOR.row = VGA_HEIGHT - 1
+  
+      offset = (VGA_CURSOR.row * VGA_WIDTH + VGA_CURSOR.col) * 2
+  
+      (VGA_BUFFER + offset).value = ch
+      (VGA_BUFFER + offset + 1).value = color
+  
+      VGA_CURSOR.col += 1
+  
+      #  Wrap around if past screen
+      if VGA_CURSOR.col >= VGA_WIDTH
+        VGA_CURSOR.col = 0
+        VGA_CURSOR.row += 1
+        if VGA_CURSOR.row >= VGA_HEIGHT
+          VGA_CURSOR.row = VGA_HEIGHT - 1
+        end
       end
     end
-
-    # Wrap around if past screen
-    # i %= VGA_SIZE
-  end
-
-  # Write a string to VGA
-  def self.puts(
-    str : String,
-    color : UInt8? = Colors::DEFAULT,
-    line : Int32? = 0,
-  ) : Nil
-    i = 0
-    while i < str.size - 1
-      ch = (str.to_unsafe + i).value
-      putchar(ch, i, line, color)
-      i += 1
-    end
-  end
   
-  def self.debug_write_at(r : Int32, c : Int32, s : String, color : UInt8 = Colors::DEFAULT)
-    off = ((r * VGA_WIDTH) + c) * 2
-    i = 0
-    ptr = s.to_unsafe
-    while i < s.bytesize
-      (VGA_BUFFER + off + (i * 2)).value = (ptr + i).value
-      (VGA_BUFFER + off + (i * 2) + 1).value = color
-      i += 1
+    # Write a string to VGA
+    def self.puts(
+      str : String,
+      color : UInt8? = Colors::DEFAULT,
+      line : Int32? = 0,
+    ) : Nil
+      i = 0
+      while i < str.size - 1
+        ch = (str.to_unsafe + i).value
+        putchar(ch, i, line, color)
+        i += 1
+      end
     end
-  end
 
-  def self.dump_cursor_and_cells
-    # Write cursor state at row 2 col 0
-    # debug_write_at(2, 0, ["CURSOR R:",VGA_CURSOR.row," C:",VGA_CURSOR.col].join(""), Colors::BLACK_ON_CYAN)
-    # Also copy first 32 bytes of VGA buffer to row 3 for inspection
-    i = 0
-    while i < 32
-      ch = (VGA_BUFFER + (i * 2)).value
-      (VGA_BUFFER + ((3 * VGA_WIDTH + i) * 2)).value = ch
-      (VGA_BUFFER + ((3 * VGA_WIDTH + i) * 2) + 1).value = Colors::BLACK_ON_LIME
-      i += 1
-    end
-  end
-  
 end