fide/fide.py

219 lines
7.0 KiB
Python
Executable File

import pygame as pg
from pygame import Rect
from piece_table import PieceTable
import os
import json
import sys
import time
import copy
from dataclasses import dataclass
from typing import List
from code import InteractiveConsole, InteractiveInterpreter
from editing import *
@dataclass(slots=True)
class Cursor:
width: float
height: float
line_num: int = 0
col: int = 0
want_col: int = 0
@dataclass(slots=True)
class Line:
piece: PieceTable
length: int
@dataclass(slots=True)
class Buffer:
lines: List[Line]
cursor: Cursor
def cursor_pos(cursor: Cursor):
return (cursor.line_num, cursor.col)
def cursor_draw(cursor: Cursor):
rect = Rect(cursor.col * cursor.width, cursor.line_num * cursor.height, 3, cursor.height)
pg.draw.rect(screen, "black", rect, width=2)
def line_create(text: str) -> Line:
return Line(PieceTable(text), len(text))
def buffer_create(text: str, cursor: Cursor) -> Buffer:
lines = []
for line in text.split('\n'):
lines.append(line_create(line))
return Buffer(lines, cursor)
def buffer_line_current(buf: Buffer) -> Line:
return buf.lines[buf.cursor.line_num]
def buffer_line_num(buf: Buffer) -> int:
return buf.cursor.line_num
def buffer_total_lines(buf: Buffer) -> int:
return len(buf.lines)
def buffer_line_len(buf: Buffer) -> int:
return buffer_line_current(buf).length
def buffer_insert_line_below(buf: Buffer, text):
line_num = buffer_line_num(buf)
buf.lines.insert(line_num + 1, line_create(text))
def buffer_newline_at_pos(buf):
curr_line = buffer_line_current(buf)
cursor = buf.cursor
if cursor.col < buffer_line_len(buf):
remainder = curr_line.length - cursor.col
line = curr_line.piece.string_at(cursor.col, remainder)
curr_line.piece.delete(cursor.col, remainder)
curr_line.length -= remainder
else:
line = ""
buffer_insert_line_below(buf, line)
cursor.line_num += 1
# Eventually when we need to be indentation aware
cursor.col = 0
cursor.want_col = 0
def buffer_delete_character_at_pos(buf):
cursor = buf.cursor
if cursor_pos(cursor) != (0,0):
if cursor.col == 0:
curr_line = buf.lines.pop(cursor.line_num)
cursor.line_num -= 1
above_row = buf.lines[cursor.line_num]
above_row.piece.insert(curr_line.piece.get_text(), above_row.length)
cursor.col = above_row.length
cursor.want_col = cursor.col
above_row.length += curr_line.length
else:
curr_line = buffer_line_current(buf)
curr_line.piece.delete(cursor.col - 1, 1)
curr_line.length -= 1
cursor.col = max(0, cursor.col - 1)
cursor.want_col = cursor.col
oswinx, oswiny = 1940,50
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (oswinx,oswiny)
clock = pg.time.Clock()
pg.init()
pg.font.init()
text_renderer = pg.font.SysFont('JetBrains Mono', 14)
screen = pg.display.set_mode((900, 900), pg.RESIZABLE)
pg.key.set_repeat(240, 10)
def load_file(path):
with open(path, 'r', encoding='utf-8') as f:
text = f.read()
f.close()
return text
@dataclass
class GlobalContext:
cursor = Cursor(width=8, height=20)
text = load_file('../gux/test.c')
current_buffer = buffer_create(text, cursor)
# global ctx
def main():
running = True
frame_count = 0
cursor_flash = 0
cursor_on = True
line_height = 20
cursor = ctx.cursor
current_buffer = ctx.current_buffer
console = InteractiveInterpreter(locals())
console.runsource('from editing import *')
key_map = {
'left': cursor_go_left,
'right': cursor_go_right,
'up': cursor_go_up,
'down': cursor_go_down
}
while running:
dt = clock.tick(120) / 1000.0
screen.fill('white')
frame_count += 1
for event in pg.event.get():
if event.type == pg.QUIT:
running = False
if event.type == pg.KEYDOWN:
cursor_on = True
cursor_flash = 0
curr_line = buffer_line_current(current_buffer)
if event.mod == 64: # Right Ctrl
if event.key == pg.K_e:
cursor.col = buffer_line_len(buf)
cursor.want_col = cursor.col
if event.key == pg.K_a:
cursor.col = 0
cursor.want_col = cursor.col
if event.key == pg.K_RETURN:
src = buffer_line_current(current_buffer).piece.get_text()
console.runsource(src[3:])
# console.runcode()
elif event.key == pg.K_RETURN:
buffer_newline_at_pos(current_buffer)
elif event.key == pg.K_BACKSPACE:
buffer_delete_character_at_pos(current_buffer)
elif event.key == pg.K_DELETE:
if cursor.col >= buffer_line_len(current_buffer):
if cursor.line_num < len(current_buffer.lines) - 1:
below_row = current_buffer.lines.pop(cursor.line_num+1)
if below_row.length > 0:
curr_line.piece.insert(below_row.piece.get_text(), curr_line.length)
curr_line.length += below_row.length
cursor.want_col = cursor.col
else:
if curr_line.length >= 1:
curr_line.piece.delete(cursor.col, 1)
curr_line.length -= 1
cursor.want_col = cursor.col
elif event.key == pg.K_LEFT:
key_map['left']()
elif event.key == pg.K_RIGHT:
key_map['right']()
elif event.key == pg.K_UP:
key_map['up']()
elif event.key == pg.K_DOWN:
key_map['down']()
elif event.key == pg.K_SPACE:
curr_line.piece.insert(u' ', cursor.col)
curr_line.length += 1
cursor.col += 1
cursor.want_col = cursor.col
elif event.key >= 33 and event.key <= 126 and event.mod < 2:
curr_line.piece.insert(event.unicode, cursor.col)
curr_line.length += 1
cursor.col += 1
cursor.want_col = cursor.col
for i,curr_line in enumerate(current_buffer.lines):
render = text_renderer.render(curr_line.piece.get_text(), True, 'black')
screen.blit(render, (0, i * line_height))
if cursor_on and cursor_flash < 0.5:
cursor_draw(cursor)
elif cursor_on:
cursor_on = False
cursor_flash = 0
elif not cursor_on and cursor_flash > 0.5:
cursor_on = True
cursor_flash = 0
cursor_flash += dt
pg.display.flip()
if __name__ == '__main__':
main()