basic visual buffer support
This commit is contained in:
parent
208e66d9fc
commit
3de29be96d
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,9 +1,9 @@
|
||||
import curses
|
||||
|
||||
|
||||
def write_buffer(stdscr, data):
|
||||
count = 0
|
||||
for line in data["buffer_list"]:
|
||||
def write_buffer(screen, data):
|
||||
for index, line in enumerate(data["buffer_list"][data["visible_y"]:]):
|
||||
if index < data["height"] - 2:
|
||||
str_line = "".join(line)
|
||||
stdscr.addstr(count, len(data["info_bar"][0]), str_line + (" " * (len(line) - 1)), curses.color_pair(1))
|
||||
count += 1
|
||||
# [data["visible_x"]:1:data["width"] - data["visible_x"]]
|
||||
screen.addstr(index, len(data["info_bar"][0]), str_line + (" " * (len(line) - 1)), curses.color_pair(1))
|
||||
|
@ -1,3 +1,6 @@
|
||||
from core import utils, buffer
|
||||
|
||||
|
||||
def cursor_mode(mode):
|
||||
if mode == "block":
|
||||
print("\033[2 q")
|
||||
@ -13,9 +16,15 @@ def cursor_mode(mode):
|
||||
|
||||
|
||||
def check_cursor(data):
|
||||
if data["cursor_y"] == len(data["buffer_list"]):
|
||||
if data["cursor_y"] + data["visible_y"] == len(data["buffer_list"]):
|
||||
data["cursor_y"] -= 1
|
||||
|
||||
if data["cursor_y"] == data["height"] - 2 and not data["cursor_y"] + data["visible_y"] == len(data["buffer_list"]):
|
||||
data["visible_y"] += 1
|
||||
|
||||
elif data["cursor_y"] == 0 and data["buffer_list"][data["visible_y"]] != data["buffer_list"][0]:
|
||||
data["visible_y"] -= 1
|
||||
|
||||
elif data["cursor_x"] > len(data["buffer_list"][data["cursor_y"]]):
|
||||
data["cursor_x"] = len(data["buffer_list"][data["cursor_y"]])
|
||||
|
||||
@ -27,9 +36,9 @@ def check_cursor(data):
|
||||
return data
|
||||
|
||||
|
||||
def move(stdscr, data):
|
||||
def move(screen, data):
|
||||
# Calculate a valid cursor position from data
|
||||
data = check_cursor(data)
|
||||
|
||||
# Move the cursor
|
||||
stdscr.move(data["cursor_y"], data["cursor_x"])
|
||||
screen.move(data["cursor_y"], data["cursor_x"])
|
||||
|
@ -1,4 +1,4 @@
|
||||
def open_file(file):
|
||||
with open(file) as f:
|
||||
def open_file(file_name):
|
||||
with open(file_name) as f:
|
||||
lines = f.readlines()
|
||||
return lines
|
||||
|
@ -1,17 +1,17 @@
|
||||
from modes import normal, insert, command
|
||||
|
||||
|
||||
def activate(stdscr, data):
|
||||
def activate(screen, data):
|
||||
if data["mode"] == "normal":
|
||||
data["mode_color"] = 6
|
||||
data = normal.activate(stdscr, data)
|
||||
data = normal.activate(screen, data)
|
||||
|
||||
elif data["mode"] == "insert":
|
||||
data["mode_color"] = 12
|
||||
data = insert.activate(stdscr, data)
|
||||
data = insert.activate(screen, data)
|
||||
|
||||
elif data["mode"] == "command":
|
||||
data["mode_color"] = 6
|
||||
data = command.activate(stdscr, data)
|
||||
data = command.activate(screen, data)
|
||||
|
||||
return data
|
||||
|
@ -23,21 +23,23 @@ def themes(data):
|
||||
return colors, icon, mode, file
|
||||
|
||||
|
||||
def refresh(stdscr, data):
|
||||
def refresh(screen, data):
|
||||
# Calculate the theme
|
||||
colors, icon, mode, file = themes(data)
|
||||
|
||||
# Render icon
|
||||
stdscr.addstr(data["height"] - 2, 0, icon,
|
||||
screen.addstr(data["height"] - 2, 0, icon,
|
||||
curses.color_pair(colors[0]) | curses.A_BOLD)
|
||||
|
||||
# Render mode
|
||||
stdscr.addstr(data["height"] - 2, len(icon), mode,
|
||||
screen.addstr(data["height"] - 2, len(icon), mode,
|
||||
curses.color_pair(colors[1]) | curses.A_BOLD)
|
||||
|
||||
# Render file name
|
||||
stdscr.addstr(data["height"] - 2, len(icon) + len(mode), file,
|
||||
screen.addstr(data["height"] - 2, len(icon) + len(mode), file,
|
||||
curses.color_pair(colors[2]) | curses.A_BOLD)
|
||||
|
||||
# Rest of the bar
|
||||
stdscr.addstr(data["height"] - 2, len(icon) + len(mode) + len(file),
|
||||
screen.addstr(data["height"] - 2, len(icon) + len(mode) + len(file),
|
||||
" " * (data["width"] - (len(icon) + len(mode) + len(file))),
|
||||
curses.color_pair(colors[3]))
|
||||
|
@ -2,36 +2,50 @@ from sys import exit
|
||||
import curses
|
||||
|
||||
|
||||
def goodbye(stdscr, data):
|
||||
# The prompt message
|
||||
saved = "All changes are saved."
|
||||
prompt = "Really quit? (y or n): "
|
||||
def refresh_window_size(screen, data):
|
||||
# Get the height and width of the screen
|
||||
data["height"], data["width"] = screen.getmaxyx()
|
||||
|
||||
# Clear the bottom line
|
||||
stdscr.addstr(data["height"] - 1, 0, " " * (data["width"] - 1), curses.color_pair(1))
|
||||
# Return the data as changes may have been made
|
||||
return data
|
||||
|
||||
|
||||
def clear_line(screen, data, line):
|
||||
# Clear the specified line
|
||||
screen.addstr(line, 0, " " * (data["width"] - 1), curses.color_pair(1))
|
||||
|
||||
|
||||
def prompt(screen, data, text):
|
||||
# Print the prompt
|
||||
stdscr.addstr(data["height"] - 1, 0, prompt, curses.color_pair(11))
|
||||
screen.addstr(data["height"] - 1, 0, text, curses.color_pair(11))
|
||||
|
||||
# Wait for and capture a key press from the user
|
||||
key = stdscr.getch()
|
||||
return screen.getch()
|
||||
|
||||
|
||||
def goodbye(screen, data):
|
||||
# Create a goodbye prompt
|
||||
key = prompt(screen, data, "Really quit? (y or n): ")
|
||||
|
||||
# Clear the bottom line
|
||||
clear_line(screen, data, data["height"] - 1)
|
||||
|
||||
if key == ord("y"):
|
||||
# Only exit if the key was "y", a confirmation
|
||||
exit()
|
||||
|
||||
# Clear the bottom line again
|
||||
stdscr.addstr(data["height"] - 1, 0, " " * (data["width"] - 1), curses.color_pair(1))
|
||||
clear_line(screen, data, data["height"] - 1)
|
||||
|
||||
|
||||
def error(stdscr, data, error_msg):
|
||||
def error(screen, data, error_msg):
|
||||
# Print the error message to the bottom line
|
||||
error_msg = f"ERROR: {error_msg}"
|
||||
stdscr.addstr(data["height"] - 1, 0, error_msg, curses.color_pair(3))
|
||||
stdscr.addstr(data["height"] - 1, len(error_msg) + 1, "(press any key) ", curses.color_pair(1))
|
||||
screen.addstr(data["height"] - 1, 0, error_msg, curses.color_pair(3))
|
||||
screen.addstr(data["height"] - 1, len(error_msg) + 1, "(press any key) ", curses.color_pair(1))
|
||||
|
||||
# Wait for a key to be pressed
|
||||
stdscr.getch()
|
||||
screen.getch()
|
||||
|
||||
# Clear the bottom line
|
||||
stdscr.addstr(data["height"] - 1, 0, " " * (data["width"] - 1), curses.color_pair(1))
|
||||
clear_line(screen, data, data["height"] - 1)
|
||||
|
@ -1,9 +1,9 @@
|
||||
import curses
|
||||
|
||||
|
||||
def start_screen(stdscr):
|
||||
def start_screen(screen):
|
||||
# Get window height and width
|
||||
height, width = stdscr.getmaxyx()
|
||||
height, width = screen.getmaxyx()
|
||||
|
||||
# Startup text
|
||||
title = "λ Lambda"
|
||||
@ -20,10 +20,10 @@ def start_screen(stdscr):
|
||||
start_y = int((height // 2) - 2)
|
||||
|
||||
# Rendering title
|
||||
stdscr.addstr(start_y, start_x_title, title, curses.color_pair(7) | curses.A_BOLD)
|
||||
screen.addstr(start_y, start_x_title, title, curses.color_pair(7) | curses.A_BOLD)
|
||||
|
||||
# Print the subtext
|
||||
for text in subtext:
|
||||
start_y += 1
|
||||
start_x = int((width // 2) - (len(text) // 2) - len(text) % 2)
|
||||
stdscr.addstr(start_y, start_x, text)
|
||||
screen.addstr(start_y, start_x, text)
|
||||
|
22
lambda.py
22
lambda.py
@ -4,7 +4,7 @@ import curses
|
||||
import argparse
|
||||
|
||||
|
||||
def start(stdscr, buffer_name, buffer_list):
|
||||
def start(screen, buffer_name, buffer_list):
|
||||
# Initialise data before starting
|
||||
data = {
|
||||
"cursor_y": 0,
|
||||
@ -16,6 +16,8 @@ def start(stdscr, buffer_name, buffer_list):
|
||||
"info_bar": [" "],
|
||||
"buffer_name": buffer_name,
|
||||
"buffer_list": buffer_list,
|
||||
"visible_y": 0,
|
||||
"visible_x": 0,
|
||||
"statusbar_theme": "filled"
|
||||
}
|
||||
|
||||
@ -27,22 +29,28 @@ def start(stdscr, buffer_name, buffer_list):
|
||||
|
||||
# Start the screen
|
||||
if data["buffer_name"] == "[No Name]":
|
||||
welcome.start_screen(stdscr)
|
||||
welcome.start_screen(screen)
|
||||
|
||||
# Main loop
|
||||
while True:
|
||||
# Get the height and width of the screen
|
||||
data["height"], data["width"] = stdscr.getmaxyx()
|
||||
data["height"], data["width"] = screen.getmaxyx()
|
||||
|
||||
# Write the buffer to the screen
|
||||
buffer.write_buffer(stdscr, data)
|
||||
buffer.write_buffer(screen, data)
|
||||
|
||||
# Activate the next mode
|
||||
data = mode.activate(stdscr, data)
|
||||
data = mode.activate(screen, data)
|
||||
|
||||
# Write the buffer to the screen
|
||||
buffer.write_buffer(screen, data)
|
||||
|
||||
# Refresh and clear the screen
|
||||
stdscr.refresh()
|
||||
stdscr.clear()
|
||||
screen.refresh()
|
||||
screen.clear()
|
||||
|
||||
# Write the buffer to the screen
|
||||
buffer.write_buffer(screen, data)
|
||||
|
||||
|
||||
def main():
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -2,10 +2,10 @@ from core import statusbar, utils
|
||||
import curses
|
||||
|
||||
|
||||
def execute(stdscr, data, commands):
|
||||
def execute(screen, data, commands):
|
||||
if not commands:
|
||||
# Quit if there are no commands, don't check anything
|
||||
return
|
||||
return data
|
||||
|
||||
for command in commands:
|
||||
if command == "w":
|
||||
@ -14,9 +14,10 @@ def execute(stdscr, data, commands):
|
||||
|
||||
elif command == "q":
|
||||
# Goodbye prompt
|
||||
utils.goodbye(stdscr, data)
|
||||
utils.goodbye(screen, data)
|
||||
|
||||
elif command == "t":
|
||||
# Theme switcher
|
||||
if data["statusbar_theme"] == "filled":
|
||||
data["statusbar_theme"] = "bare"
|
||||
|
||||
@ -24,29 +25,29 @@ def execute(stdscr, data, commands):
|
||||
data["statusbar_theme"] = "filled"
|
||||
|
||||
else:
|
||||
utils.error(stdscr, data, f"Not an editor command: '{command}'")
|
||||
utils.error(screen, data, f"Not an editor command: '{command}'")
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def activate(stdscr, data):
|
||||
def activate(screen, data):
|
||||
# Initialise variables
|
||||
commands = []
|
||||
|
||||
# Visibly switch to command mode
|
||||
statusbar.refresh(stdscr, data)
|
||||
stdscr.addstr(data["height"]-1, 0, ":")
|
||||
stdscr.move(data["height"]-1, 1)
|
||||
statusbar.refresh(screen, data)
|
||||
screen.addstr(data["height"]-1, 0, ":")
|
||||
screen.move(data["height"]-1, 1)
|
||||
|
||||
# Main loop
|
||||
while True:
|
||||
# Get a key inputted by the user
|
||||
key = stdscr.getch()
|
||||
key = screen.getch()
|
||||
|
||||
# Handle subtracting a key (backspace)
|
||||
if key == curses.KEY_BACKSPACE:
|
||||
# Write whitespace over characters to refresh it
|
||||
stdscr.addstr(data["height"]-1, 1, " " * len(commands))
|
||||
screen.addstr(data["height"]-1, 1, " " * len(commands))
|
||||
|
||||
if commands:
|
||||
# Subtract a character
|
||||
@ -63,10 +64,10 @@ def activate(stdscr, data):
|
||||
|
||||
elif key in (curses.KEY_ENTER, ord('\n'), ord('\r'), ord(":"), ord(";")):
|
||||
# Execute commands
|
||||
data = execute(stdscr, data, commands)
|
||||
data = execute(screen, data, commands)
|
||||
|
||||
# Clear the bottom bar
|
||||
stdscr.addstr(data["height"] - 1, 0, " " * (data["width"] - 1))
|
||||
screen.addstr(data["height"] - 1, 0, " " * (data["width"] - 1))
|
||||
|
||||
# Return to normal mode after executing a command
|
||||
data["mode"] = "normal"
|
||||
@ -83,7 +84,7 @@ def activate(stdscr, data):
|
||||
friendly_command = "".join(commands)
|
||||
|
||||
# Write the commands to the screen
|
||||
stdscr.addstr(data["height"]-1, 1, friendly_command)
|
||||
screen.addstr(data["height"]-1, 1, friendly_command)
|
||||
|
||||
# Move the cursor the end of the commands
|
||||
stdscr.move(data["height"]-1, len(commands)+1)
|
||||
screen.move(data["height"]-1, len(commands)+1)
|
||||
|
@ -5,22 +5,22 @@ def execute(data, key):
|
||||
return data
|
||||
|
||||
|
||||
def activate(stdscr, data):
|
||||
def activate(screen, data):
|
||||
# Refresh the status bar with a different colour for insert
|
||||
data["statusbar_colors"] = [8, 12, 14, 2]
|
||||
statusbar.refresh(stdscr, data)
|
||||
statusbar.refresh(screen, data)
|
||||
|
||||
# Refresh the status bar
|
||||
statusbar.refresh(stdscr, data)
|
||||
statusbar.refresh(screen, data)
|
||||
|
||||
# Move the cursor
|
||||
cursor.move(stdscr, data)
|
||||
cursor.move(screen, data)
|
||||
|
||||
# Switch to a line cursor
|
||||
cursor.cursor_mode("line")
|
||||
|
||||
# Wait for and capture a key press from the user
|
||||
key = stdscr.getch()
|
||||
key = screen.getch()
|
||||
|
||||
# Exit insert mode
|
||||
if key == 27:
|
||||
|
@ -1,4 +1,5 @@
|
||||
from core import statusbar, cursor
|
||||
import curses
|
||||
|
||||
|
||||
def execute(data, key):
|
||||
@ -34,18 +35,18 @@ def execute(data, key):
|
||||
return data
|
||||
|
||||
|
||||
def activate(stdscr, data):
|
||||
def activate(screen, data):
|
||||
# Refresh the status bar
|
||||
statusbar.refresh(stdscr, data)
|
||||
statusbar.refresh(screen, data)
|
||||
|
||||
# Move the cursor
|
||||
cursor.move(stdscr, data)
|
||||
cursor.move(screen, data)
|
||||
|
||||
# Switch the cursor to a block
|
||||
cursor.cursor_mode("block")
|
||||
|
||||
# Wait for and capture a key press from the user
|
||||
key = stdscr.getch()
|
||||
key = screen.getch()
|
||||
|
||||
# Check against the keybindings
|
||||
data = execute(data, key)
|
||||
|
Loading…
Reference in New Issue
Block a user