godot-xterm/addons/godot_xterm/buffer.gd
2020-05-10 01:42:19 +07:00

271 lines
5.7 KiB
GDScript

# Copyright (c) 2020 The GodotXterm authors. All rights reserved.
# License MIT
extends Reference
const CharData = preload("res://addons/godot_xterm/char_data.gd")
const Decoder = preload("res://addons/godot_xterm/input/text_decoder.gd")
const MAX_BUFFER_SIZE = 32768 # 32 KiB
# Erase in Line (EL)
enum {EL_RIGHT, EL_LEFT, EL_ALL}
enum {FONT_NORMAL, FONT_BOLD, FONT_BLINK}
# Places a tab stop after every 8 columns.
var tabWidth = 8
var rows = [[]] # array of CharData
var fg = Color(1.0, 1.0, 1.0) # foreground color
var bg = Color(0.0, 0.0, 0.0) # background color
var font # font
var font_flags = FONT_NORMAL
var crow = 0 setget _set_crow # cursor's row
var ccol = 0 setget _set_ccol # cursor's column
var ccol_saved: int
var crow_saved: int
var num_rows = 20
var num_cols = 70
var savedBuffer
var savedCursorRow
var savedCursorCol
func _init(num_rows: int, num_columns: int, alternate: bool = false):
rows = []
rows.resize(num_rows)
for i in range(rows.size()):
var cols = []
cols.resize(num_columns)
for j in range(cols.size()):
cols[j] = CharData.new(" ", bg, fg, font_flags)
rows[i] = cols
func _get_buffer_size():
# Get the size of the (virtual) buffer.
# Count each CharData as one byte even though it might be multiple bytes
# in the case of unicode characters.
var size = 0
for row in rows:
size += row.size()
return size
func _set_rows(rows):
print("rows: ", rows)
func _set_crow(row: int):
print("setting crow")
# Ensure there are enoungh rows in the
# buffer for the new cursor position.
if row >= rows.size():
rows.resize(row + 1)
# resize() uses null for new elements.
# but a row should be an array so we
# need to replace null values.
for i in range(rows.size()):
if rows[i] == null:
rows[i] = []
crow = row
func _set_ccol(col: int):
# Ensure there are enough columns in the
# row for the new cursor position.
print("da size: ", rows[crow].size())
if col >= rows[crow].size():
rows[crow].resize(col + 1)
print("da new size: ", rows[crow].size())
for i in range(rows[crow].size()):
if rows[crow][i] == null:
rows[crow][i] = CharData.new(' ', bg, fg)
ccol = col
func save_cursor():
ccol_saved = ccol
crow_saved = crow
func restore_cursor():
ccol = ccol_saved
crow = crow_saved
func insert_at_cursor(d, start: int = 0, end: int = 1):
var string
if typeof(d) == TYPE_ARRAY:
string = Decoder.utf32_to_string(d.slice(start, end - 1))
else:
string = d
var row = rows[crow]
for i in range(string.length()):
var data = CharData.new(string[i], bg, fg, font_flags)
if ccol < row.size():
row[ccol] = data
else:
row.resize(ccol)
for i in range(row.size()):
if row[i] == null:
row[i] = CharData.new(' ', bg, fg, font_flags)
row.append(data)
# Update the cursor position.
ccol += 1
func insert_tab():
print("Insert a tab!")
# Insert a space.
insert_at_cursor(' ')
# Keep inserting spaces until cursor is at next Tab stop.
while ccol % tabWidth != 0:
insert_at_cursor(' ')
# cr
func carriage_return():
ccol = 0
# lf
func line_feed():
rows.resize(rows.size() + 1)
rows[-1] = []
crow = crow + 1
# bs
# Deletes the element before the current cursor position.
func backspace():
rows[crow].remove(ccol - 1)
ccol = ccol - 1
# cup
# Move the cursor to the given row and column.
# For example cursor_position(0, 0) would move
# the cursor to the top left corner of the terminal.
func cursor_position(params: Array) -> void:
var row = params[0] if params.size() > 0 else 1
var col = params[1] if params.size() > 1 else 1
# Origin is (0,0) so row 1, col 1 would be 0,0.
if col != 0:
self.ccol = col - 1
else:
self.ccol = 0
if row != 0:
self.crow = row - 1
else:
self.crow = 0
# ed 3
func erase_saved_lines():
rows = [[]]
print("saved lines erased")
# el
func erase_in_line(section):
return
match section:
EL_LEFT, EL_ALL:
for i in range(0, ccol):
rows[crow][i] = CharData.new(" ")
print("Erased the thing")
if section == EL_ALL:
continue
EL_RIGHT, _:
for i in range(ccol, rows[crow].size()):
rows[crow][i] = CharData.new(" ")
print("Erased the thing")
# ed 0 (default)
func erase_below():
# Erase from the cursor through to the end of the display.
save_cursor()
while crow < num_rows:
erase_in_line(EL_RIGHT)
_set_ccol(0)
_set_crow(crow + 1)
restore_cursor()
func set_scrolling_region(top: int, bottom: int):
print("set_scrolling_position")
# Not sure what this does yet.
# Make default be full window size.
pass
func set_font(fontState: int, set: bool = true):
match fontState:
FONT_NORMAL:
pass
func set_font_flag(flag: int, set: bool = true):
print("setting font flag!")
if set: # Set the flag
font_flags |= (1 << flag)
else: # Clear the flag
font_flags &= ~(1 << flag)
print("font flag is set!")
print(font_flags)
# Clear all font flags. Returns font to default state.
func reset_font_flags():
font_flags = FONT_NORMAL
# setf
func set_foreground(color: Color = Color(1.0, 1.0, 1.0)):
fg = color
# setb
func set_background(color: Color = Color(0.0, 0.0, 0.0)):
bg = color
# setaf
func set_a_foreground(params):
pass
# setab
func set_a_background(params):
pass
func reset_sgr():
set_foreground()
set_background()
reset_font_flags()
func repeat_preceding_character(times: int = 0):
var preceding_char
if ccol == 0:
preceding_char = rows[crow-1][-1]
else:
preceding_char = rows[crow][ccol-1]
print("Repeating preceding char ", preceding_char.ch, " ", times, " times")
for i in range(times):
insert_at_cursor(preceding_char.ch)
# Save the buffer (useful when switching to the alternate buffer)
func save():
savedBuffer = rows
savedCursorCol = ccol
savedCursorRow = crow
# Full Reset
func reset():
rows = [[]]
crow = 0
ccol = 0
fg = Color(1.0, 1.0, 1.0)
bg = Color(0.0, 0.0, 0.0)