hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/kernel/console.rv
blob: 65fe03cdb7320c427fa8c89fe59f1ffd34182b14 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
const FW = 8  # glyph width in pixels
const FH = 16 # glyph height in pixels (8x16 vga bitmap font)
const FG = 0xd0d0d0
const CON_BG = 0x101018
const CUR = 0x50fa7b

global con = {
  col = 0, row = 0, scale = 1, shown = :false, cur_x = 0, cur_y = 0, blink = 0,

  # cell size in pixels at the current zoom
  cell_w = fn(self) FW * self.scale,
  cell_h = fn(self) FH * self.scale,
  cols = fn(self) fb_width() / self:cell_w(),
  rows = fn(self) fb_height() / self:cell_h(),

  draw_glyph = fn(self, col, row, ch) do
    const x0 = col * self:cell_w()
    const y0 = row * self:cell_h()
    fill_rect(x0, y0, self:cell_w(), self:cell_h(), CON_BG) # clear the cell
    const code = ch:ascii()
    if code < 32 return :nil
    if code > 127 return :nil
    const glyph = FONT[code - 32]
    for fy in 0..FH do
      const bits = glyph[fy]
      for fx in 0..FW do
        if (bits shr fx) band 1 == 1 fill_rect(x0 + fx * self.scale, y0 + fy * self.scale, self.scale, self.scale, FG)
      end
    end
  end,

  newline = fn(self) do
    self.col = 0
    self.row += 1
    if self.row >= self:rows() do
      fb_scroll(self:cell_h(), CON_BG)
      self.row = self:rows() - 1
    end
  end,

  # we dont do shift/cntrl, thats a job for future me lmao
  # NOTE: future me kinda delt with it, i was mad drunk
  putc = fn(self, ch) do
    const code = ch:ascii()
    if code == 10 do self:newline() return :nil end # \n
    if code == 13 do self.col = 0 return :nil end   # \r
    if code == 8 do                                 # backspace: move left
      if self.col > 0 self.col -= 1
      return :nil
    end
    if code < 32 return :nil
    self:draw_glyph(self.col, self.row, ch)
    self.col += 1
    if self.col >= self:cols() self:newline()
  end,

  clear = fn(self) do
    fill_rect(0, 0, fb_width(), fb_height(), CON_BG)
    self.col = 0
    self.row = 0
  end,

  # the cursor is an overlay block. its cleared before any drawing and shown after,
  # so it never sits under a glyph, cur_x/cur_y remember where it was actually drawn
  # so we always clear the right cell even after the head moved (backspace and shit)
  cursor_clear = fn(self) do
    if self.shown do
      fill_rect(self.cur_x * self:cell_w(), self.cur_y * self:cell_h(), self:cell_w(), self:cell_h(), CON_BG)
      self.shown = :false
    end
  end,

  cursor_show = fn(self) do
    self.cur_x = self.col
    self.cur_y = self.row
    fill_rect(self.cur_x * self:cell_w(), self.cur_y * self:cell_h(), self:cell_w(), self:cell_h(), CUR)
    self.shown = :true
  end,

  # render every byte the serial mirror has buffered
  drain = fn(self) do
    let byte = serial_next()
    while byte >= 0 do self:putc(string.of_ascii(byte)) byte = serial_next() end
  end,
}

fn puts(str) serial_puts(str)

global flush_console = fn() do
  con:cursor_clear()
  con:drain()
  con.blink = 0
  con:cursor_show()
end

global on_tick = fn(ticks) do
  let byte = serial_next()
  if byte >= 0 do
    con:cursor_clear()
    con:putc(string.of_ascii(byte))
    con:drain()
    con.blink = 0
    con:cursor_show()
    return :nil
  end
  if proc_exited() do
    con:cursor_clear()
    puts("% ")
    con:drain()
    con.blink = 0
    con:cursor_show()
    return :nil
  end
  con.blink += 1
  if con.blink >= 50 do
    con.blink = 0
    if con.shown con:cursor_clear() else con:cursor_show()
  end
end