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