2022-03-19 15:13:28 +00:00
|
|
|
import argparse
|
|
|
|
import curses
|
|
|
|
import os
|
|
|
|
|
2022-04-14 18:24:45 +01:00
|
|
|
from core import colors, cursors, buffers, modes, utils
|
|
|
|
from core.buffers import Buffer
|
|
|
|
from core.components import Components
|
|
|
|
|
2022-03-19 15:13:28 +00:00
|
|
|
|
|
|
|
class Lambda:
|
2022-04-15 13:44:24 +01:00
|
|
|
def __init__(self, buffer: Buffer = None, config: dict = None):
|
2022-03-19 15:13:28 +00:00
|
|
|
self.screen = curses.initscr()
|
2022-04-14 18:24:45 +01:00
|
|
|
self.config = config or {"icon": "λ"}
|
2022-04-15 13:44:24 +01:00
|
|
|
self.buffer = buffer or [""]
|
2022-04-14 18:24:45 +01:00
|
|
|
self.mode = "normal"
|
2022-03-19 15:13:28 +00:00
|
|
|
self.cursor = [0, 0]
|
2022-04-14 18:24:45 +01:00
|
|
|
self.raw_cursor = [0, 0]
|
2022-03-19 19:19:25 +00:00
|
|
|
self.offset = [0, 0]
|
|
|
|
self.height = 0
|
|
|
|
self.width = 0
|
|
|
|
self.safe_height = 0
|
|
|
|
self.safe_width = 0
|
2022-04-15 13:44:24 +01:00
|
|
|
self.components = Components(self)
|
2022-03-19 15:13:28 +00:00
|
|
|
|
|
|
|
def update_dimensions(self):
|
2022-03-19 15:41:40 +00:00
|
|
|
# Calculate the entire height and width of the terminal
|
2022-03-19 15:13:28 +00:00
|
|
|
self.height, self.width = self.screen.getmaxyx()
|
2022-03-19 15:41:40 +00:00
|
|
|
|
|
|
|
# Calculate the safe area for the buffer by removing heights & widths of components
|
2022-04-14 18:24:45 +01:00
|
|
|
self.safe_height = self.height - len(self.components.components["bottom"]) - 2
|
|
|
|
self.safe_width = self.width - self.components.get_component_width(self.components.components["left"]) - 1
|
|
|
|
|
|
|
|
def refresh(self):
|
2022-04-15 13:44:24 +01:00
|
|
|
# Calculate the cursor position in the file
|
2022-04-14 18:24:45 +01:00
|
|
|
self.cursor[0], self.cursor[1] = self.raw_cursor[0] + self.offset[0], self.raw_cursor[1] + self.offset[1]
|
2022-03-19 15:13:28 +00:00
|
|
|
|
2022-03-19 19:19:25 +00:00
|
|
|
# Update the dimensions of the terminal
|
2022-03-19 15:13:28 +00:00
|
|
|
self.update_dimensions()
|
|
|
|
|
2022-04-14 18:24:45 +01:00
|
|
|
# Write the buffer to the screen
|
|
|
|
self.buffer.render(self)
|
2022-03-19 19:19:25 +00:00
|
|
|
|
2022-03-19 15:13:28 +00:00
|
|
|
# Refresh the on-screen components
|
|
|
|
self.components.render(self)
|
|
|
|
|
|
|
|
# Move the cursor
|
2022-03-19 19:19:25 +00:00
|
|
|
cursors.move(self)
|
2022-03-19 15:13:28 +00:00
|
|
|
|
|
|
|
def start(self):
|
2022-03-19 16:34:48 +00:00
|
|
|
# Change the escape key delay to 25ms
|
|
|
|
# Fixes an issue where the "esc" key takes way too long to press
|
|
|
|
os.environ.setdefault("ESCDELAY", "25")
|
|
|
|
|
2022-03-19 15:13:28 +00:00
|
|
|
# Initialise colors
|
|
|
|
colors.init_colors()
|
|
|
|
|
|
|
|
# Change the cursor shape
|
2022-03-19 19:19:25 +00:00
|
|
|
cursors.mode("block")
|
2022-03-19 15:13:28 +00:00
|
|
|
|
2022-03-19 15:41:40 +00:00
|
|
|
# Don't echo any key-presses
|
2022-03-19 15:13:28 +00:00
|
|
|
curses.noecho()
|
|
|
|
|
|
|
|
# Show a welcome message if lambda opens with no file
|
|
|
|
if not self.buffer.path:
|
|
|
|
utils.welcome(self.screen)
|
|
|
|
|
|
|
|
# Main loop
|
|
|
|
self.run()
|
|
|
|
|
|
|
|
def run(self):
|
2022-03-19 15:41:40 +00:00
|
|
|
# The main loop, which runs until the user quits
|
2022-03-19 15:13:28 +00:00
|
|
|
while True:
|
2022-03-19 19:19:25 +00:00
|
|
|
# Update the screen variables
|
2022-04-14 18:24:45 +01:00
|
|
|
self.refresh()
|
2022-03-19 15:13:28 +00:00
|
|
|
|
|
|
|
# Wait for a keypress
|
|
|
|
key = self.screen.getch()
|
|
|
|
|
|
|
|
# Handle the key
|
|
|
|
modes.handle_key(self, key)
|
|
|
|
|
|
|
|
# Refresh and clear the screen
|
|
|
|
self.screen.refresh()
|
2022-04-14 18:24:45 +01:00
|
|
|
self.screen.erase()
|
2022-03-19 15:13:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
def main():
|
2022-03-19 15:41:40 +00:00
|
|
|
# Shell arguments
|
2022-03-19 15:13:28 +00:00
|
|
|
parser = argparse.ArgumentParser(description="Next generation hackable text editor for nerds.")
|
|
|
|
parser.add_argument("file", metavar="file", type=str, nargs="?",
|
|
|
|
help="The name of a file for lambda to open")
|
|
|
|
|
2022-03-19 15:41:40 +00:00
|
|
|
# Collect the arguments passed into lambda at the shell
|
2022-03-19 15:13:28 +00:00
|
|
|
args = parser.parse_args()
|
|
|
|
|
2022-03-19 15:41:40 +00:00
|
|
|
# Load the file into a Buffer object
|
2022-03-19 15:13:28 +00:00
|
|
|
buffer = buffers.load_file(args.file)
|
|
|
|
|
2022-03-19 19:19:25 +00:00
|
|
|
# Load the config
|
|
|
|
config = utils.load_config()
|
|
|
|
|
2022-03-19 15:41:40 +00:00
|
|
|
# Load lambda with the buffer object
|
2022-03-19 19:19:25 +00:00
|
|
|
screen = Lambda(buffer, config)
|
2022-03-19 15:13:28 +00:00
|
|
|
|
2022-03-19 15:41:40 +00:00
|
|
|
# Start the screen, this will loop until exit
|
2022-03-19 15:13:28 +00:00
|
|
|
try:
|
|
|
|
screen.start()
|
|
|
|
|
2022-03-19 15:41:40 +00:00
|
|
|
# KeyboardInterrupt is thrown when <C-c> is pressed (exit)
|
2022-03-19 15:13:28 +00:00
|
|
|
except KeyboardInterrupt:
|
2022-04-14 18:24:45 +01:00
|
|
|
utils.gracefully_exit()
|
2022-03-19 15:13:28 +00:00
|
|
|
|
2022-03-19 15:41:40 +00:00
|
|
|
# Excepts *any* errors that occur
|
2022-03-19 15:13:28 +00:00
|
|
|
except Exception as exception:
|
2022-03-19 16:34:48 +00:00
|
|
|
utils.fatal_error(exception)
|
2022-03-19 15:13:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|