Clean up, modularisation & refactoring

This commit is contained in:
Maddie H 2022-04-20 11:47:12 +01:00
parent f312672152
commit 9126abc6d5
9 changed files with 101 additions and 65 deletions

View File

@ -1,13 +1,17 @@
# λ lambda
Next generation hackable text editor for nerds.
### Let it be known!
Lambda is in *very* early stages at the moment. Features may change completely, or even be removed.<br>
Don't expect lambda to stay the way it is. Updates are pushed often.
### Overview
Lambda is a similar text editor to `vim` or `kakoune`.<br>
However, it takes a different approach to most of the features seen in other editors.
- Lambda is written in Python, so it is easy to hack and learn.
- It also has a good amount of comments!
- Lambda is incredibly modular, so you can easily add new features.
@ -22,6 +26,7 @@ However, it takes a different approach to most of the features seen in other edi
- Lambda has much better default keybindings than other text editors.
### Getting started
```bash
git clone https://github.com/SpyHoodle/lambda.git # Clone the repository
cd lambda # Enter lambda directory

View File

@ -21,17 +21,38 @@ class Buffer:
instance.components.components["left"]) + len(line), " " * (instance.safe_width - len(line)))
@staticmethod
def remove_char(instance):
# Remove a character from a string at a given index
instance.buffer.data[instance.cursor[0]] = instance.buffer.data[instance.cursor[0]][:(instance.cursor[1] - 1)] \
+ instance.buffer.data[instance.cursor[0]][(instance.cursor[1] - 1) + 1:]
def delete_line(instance, y: int = None):
# Default to the cursor position
y = y or instance.cursor[0]
# Remove a line from the buffer
instance.buffer.data.pop(y)
@staticmethod
def insert_char(instance, char: (str, chr)):
# Insert a character into a string at a given index
instance.buffer.data[instance.cursor[0]] = instance.buffer.data[instance.cursor[0]][:instance.cursor[1]] + \
char + \
instance.buffer.data[instance.cursor[0]][instance.cursor[1]:]
def insert_line(instance, y: int = None):
# Default to the cursor position
y = y or instance.cursor[0]
# Insert a line into the buffer
instance.buffer.data.insert(y, "")
@staticmethod
def delete_char(instance, y: int = None, x: int = None):
# Default to the cursor position
y = y or instance.cursor[0]
x = x or instance.cursor[1]
# Remove a character from the line at a given index
instance.buffer.data[y] = instance.buffer.data[y][:x - 1] + instance.buffer.data[y][x:]
@staticmethod
def insert_char(instance, char: (str, chr), y: int = None, x: int = None):
# Default to the cursor position
y = y or instance.cursor[0]
x = x or instance.cursor[1]
# Insert a character into the line at a given index
instance.buffer.data[y] = instance.buffer.data[y][:x] + char + instance.buffer.data[y][x:]
def open_file(file_path):

View File

@ -18,7 +18,7 @@ class StatusBar:
def render(self, instance):
# Clear the status bar
utils.clear(instance, instance.height - 2, 0)
utils.clear_line(instance, instance.height - 2, 0)
# Update variables
self.update(instance)

View File

@ -17,12 +17,12 @@ def gracefully_exit():
sys.exit()
def clear(instance, y: int, x: int):
def clear_line(instance, y: int, x: int):
# Clear the line at the screen at position y, x
instance.screen.insstr(y, x, " " * (instance.width - x))
def pause(message: str):
def pause_screen(message: str):
# End the curses session
curses.endwin()
@ -40,17 +40,22 @@ def save_file(instance, file_path: str, data: list):
# Save the data to the file
with open(file_path, "w") as f:
try:
# For each line in the file
for index, line in enumerate(data):
if index == len(data) - 1:
# If this is the last line, write it without a newline
f.write(line)
else:
# Otherwise, write the line with a newline
f.write(f"{line}\n")
except Exception:
except (OSError, IOError):
# If the file could not be written, show an error message
error(instance, f"File {file_path} could not be saved.")
def load_config() -> dict:
def load_config_file() -> dict:
# Parse the path of the config file
config_file_path = f"{Path.home()}/.config/lambda/config.json"
@ -60,10 +65,7 @@ def load_config() -> dict:
return load_file(config_file_path)
def welcome(screen):
# Get window height and width
height, width = screen.getmaxyx()
def welcome(instance):
# Startup text
title = "λ Lambda"
subtext = [
@ -75,17 +77,17 @@ def welcome(screen):
]
# Centering calculations
start_x_title = int((width // 2) - (len(title) // 2) - len(title) % 2)
start_y = int((height // 2) - 2)
start_x_title = int((instance.safe_width // 2) - (len(title) // 2) - len(title) % 2 + 2)
start_y = int((instance.safe_height // 2) - 1)
# Rendering title
screen.addstr(start_y, start_x_title, title, curses.color_pair(7) | curses.A_BOLD)
instance.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)
screen.addstr(start_y, start_x, text)
start_x = int((instance.safe_width // 2) - (len(text) // 2) - len(text) % 2 + 2)
instance.screen.addstr(start_y, start_x, text)
def prompt(instance, message: str, color: int = 1) -> (list, None):
@ -93,7 +95,7 @@ def prompt(instance, message: str, color: int = 1) -> (list, None):
inp = []
# Write whitespace over characters to refresh it
clear(instance, instance.height - 1, len(message) + len(inp) - 1)
clear_line(instance, instance.height - 1, len(message) + len(inp) - 1)
# Write the message to the screen
instance.screen.addstr(instance.height - 1, 0, message, curses.color_pair(color))
@ -105,7 +107,7 @@ def prompt(instance, message: str, color: int = 1) -> (list, None):
# Subtracting a key (backspace)
if key in (curses.KEY_BACKSPACE, 127, '\b'):
# Write whitespace over characters to refresh it
clear(instance, instance.height - 1, len(message) + len(inp) - 1)
clear_line(instance, instance.height - 1, len(message) + len(inp) - 1)
if inp:
# Subtract a character from the input list
@ -148,7 +150,7 @@ def press_key_to_continue(instance, message: str, color: int = 1):
cursors.mode("hidden")
# Clear the bottom of the screen
clear(instance, instance.height - 1, 0)
clear_line(instance, instance.height - 1, 0)
# Write the entire message to the screen
instance.screen.addstr(instance.height - 1, 0, message, curses.color_pair(color))
@ -158,7 +160,7 @@ def press_key_to_continue(instance, message: str, color: int = 1):
instance.screen.getch()
# Clear the bottom of the screen
clear(instance, instance.height - 1, 0)
clear_line(instance, instance.height - 1, 0)
# Show the cursor
cursors.mode("visible")
@ -196,7 +198,7 @@ def goodbye(instance):
# Clear the prompt if the user cancels
else:
clear(instance, instance.height - 1, 0)
clear_line(instance, instance.height - 1, 0)
except KeyboardInterrupt:
# If the user presses Ctrl+C, just exit

View File

@ -6,6 +6,6 @@ cp -rf . ~/.local/share/lambda
# Copy lambda launcher
chmod +x ./lambda
rm -r ~/.local/bin/lambda
rm -rf ~/.local/bin/lambda
ln -s ~/.local/share/lambda/lambda ~/.local/bin/lambda
chmod +x ~/.local/bin/lambda

20
main.py
View File

@ -62,12 +62,17 @@ class Lambda:
# Show a welcome message if lambda opens with no file
if not self.buffer.path:
utils.welcome(self.screen)
# Update the screen variables
self.refresh()
# Show the welcome message
utils.welcome(self)
# Main loop
self.run()
def run(self):
try:
# The main loop, which runs until the user quits
while True:
# Update the screen variables
@ -82,6 +87,13 @@ class Lambda:
# Refresh and clear the screen
self.screen.erase()
except KeyboardInterrupt: # Ctrl-C
# Create a goodbye prompt
utils.goodbye(self)
# Run the main loop again
self.run()
def main():
# Shell arguments
@ -96,7 +108,7 @@ def main():
buffer = buffers.load_file(args.file)
# Load the config
config = utils.load_config()
config = utils.load_config_file()
# Load lambda with the buffer object
instance = Lambda(buffer, config)
@ -105,10 +117,6 @@ def main():
try:
instance.start()
# KeyboardInterrupt is thrown when <C-c> is pressed (exit)
except KeyboardInterrupt:
utils.goodbye(instance)
# Excepts *any* errors that occur
except Exception as exception:
utils.fatal_error(exception)

View File

@ -11,7 +11,7 @@ def execute(instance, key):
elif key in (curses.KEY_BACKSPACE, 127, '\b'): # Backspace
if instance.cursor[1] > 0:
# Delete the character before the cursor
instance.buffer.remove_char(instance)
instance.buffer.delete_char(instance)
# Move the cursor one to the left
cursors.push(instance, 3)