Fortran · 3945 bytes Raw Blame History
1 module scrollback_mod
2 use cell_mod
3 implicit none
4 private
5
6 public :: scrollback_t
7 public :: scrollback_init, scrollback_destroy
8 public :: scrollback_push_line, scrollback_get_line
9 public :: scrollback_clear, scrollback_count
10
11 integer, parameter :: DEFAULT_CAPACITY = 10000
12
13 type :: scrollback_t
14 type(cell_t), allocatable :: lines(:,:) ! (line_index, column)
15 integer :: capacity = 0 ! Maximum lines to store
16 integer :: cols = 0 ! Columns per line
17 integer :: count = 0 ! Current number of lines stored
18 integer :: head = 0 ! Next write position (0-based circular)
19 logical :: initialized = .false.
20 end type scrollback_t
21
22 contains
23
24 ! Initialize scrollback buffer
25 subroutine scrollback_init(sb, cols, capacity)
26 type(scrollback_t), intent(inout) :: sb
27 integer, intent(in) :: cols
28 integer, intent(in), optional :: capacity
29
30 if (present(capacity)) then
31 sb%capacity = capacity
32 else
33 sb%capacity = DEFAULT_CAPACITY
34 end if
35
36 sb%cols = cols
37 sb%count = 0
38 sb%head = 0
39
40 allocate(sb%lines(sb%capacity, cols))
41
42 ! Initialize all cells to spaces
43 sb%lines%codepoint = 32
44 sb%lines%fg = default_fg
45 sb%lines%bg = default_bg
46 sb%lines%attrs = 0
47
48 sb%initialized = .true.
49 end subroutine scrollback_init
50
51 ! Destroy scrollback buffer
52 subroutine scrollback_destroy(sb)
53 type(scrollback_t), intent(inout) :: sb
54
55 if (allocated(sb%lines)) deallocate(sb%lines)
56 sb%capacity = 0
57 sb%cols = 0
58 sb%count = 0
59 sb%head = 0
60 sb%initialized = .false.
61 end subroutine scrollback_destroy
62
63 ! Push a line into scrollback (circular buffer)
64 subroutine scrollback_push_line(sb, line, cols)
65 type(scrollback_t), intent(inout) :: sb
66 type(cell_t), intent(in) :: line(:)
67 integer, intent(in) :: cols
68 integer :: col, copy_cols
69
70 if (.not. sb%initialized) return
71 if (sb%capacity <= 0) return
72
73 ! Calculate how many columns to copy
74 copy_cols = min(cols, sb%cols, size(line))
75
76 ! Write to current head position (1-based index)
77 do col = 1, copy_cols
78 sb%lines(sb%head + 1, col) = line(col)
79 end do
80
81 ! Clear remaining columns if line is shorter
82 do col = copy_cols + 1, sb%cols
83 sb%lines(sb%head + 1, col) = cell_t(32, default_fg, default_bg, 0)
84 end do
85
86 ! Advance head (circular)
87 sb%head = mod(sb%head + 1, sb%capacity)
88
89 ! Update count (max out at capacity)
90 if (sb%count < sb%capacity) then
91 sb%count = sb%count + 1
92 end if
93 end subroutine scrollback_push_line
94
95 ! Get a line from scrollback
96 ! offset: 0 = most recent line, 1 = second most recent, etc.
97 subroutine scrollback_get_line(sb, offset, line, cols)
98 type(scrollback_t), intent(in) :: sb
99 integer, intent(in) :: offset
100 type(cell_t), intent(out) :: line(:)
101 integer, intent(in) :: cols
102 integer :: idx, col, copy_cols
103
104 ! Initialize output to spaces
105 do col = 1, min(cols, size(line))
106 line(col) = cell_t(32, default_fg, default_bg, 0)
107 end do
108
109 if (.not. sb%initialized) return
110 if (offset < 0 .or. offset >= sb%count) return
111
112 ! Calculate actual index in circular buffer
113 ! head points to next write position, so most recent is at head-1
114 idx = mod(sb%head - 1 - offset + sb%capacity, sb%capacity) + 1
115
116 ! Copy line data
117 copy_cols = min(cols, sb%cols, size(line))
118 do col = 1, copy_cols
119 line(col) = sb%lines(idx, col)
120 end do
121 end subroutine scrollback_get_line
122
123 ! Clear scrollback buffer
124 subroutine scrollback_clear(sb)
125 type(scrollback_t), intent(inout) :: sb
126
127 sb%count = 0
128 sb%head = 0
129 end subroutine scrollback_clear
130
131 ! Get number of lines in scrollback
132 function scrollback_count(sb) result(n)
133 type(scrollback_t), intent(in) :: sb
134 integer :: n
135
136 n = sb%count
137 end function scrollback_count
138
139 end module scrollback_mod
140